From e204c4e13ad639727aa16f91df7bf3e74c0608bb Mon Sep 17 00:00:00 2001 From: Salih Date: Sun, 19 Feb 2023 18:12:36 +0300 Subject: [PATCH 01/28] Added AbpBaseTagHelper --- .../DatePicker/AbpDatePickerBaseTagHelper.cs | 147 ++++ .../AbpDatePickerBaseTagHelperService.cs | 643 ++++++++++++++++++ .../DatePicker/AbpDatePickerDrops.cs | 8 + .../DatePicker/AbpDatePickerOpens.cs | 8 + .../DatePicker/AbpDatePickerRange.cs | 47 ++ .../DatePicker/AbpDatePickerWeekNumbers.cs | 8 + 6 files changed, 861 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs new file mode 100644 index 0000000000..5fbe1a2c7e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs @@ -0,0 +1,147 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +public abstract class + AbpDatePickerBaseTagHelper : AbpTagHelper> + where TTagHelper : AbpDatePickerBaseTagHelper + +{ + public string Label { get; set; } + + public string LabelTooltip { get; set; } + + public string LabelTooltipIcon { get; set; } = "bi-info-circle"; + + public string LabelTooltipPlacement { get; set; } = "right"; + + public bool LabelTooltipHtml { get; set; } = false; + + [HtmlAttributeName("info")] + public string InfoText { get; set; } + + [HtmlAttributeName("disabled")] + public bool IsDisabled { get; set; } = false; + + [HtmlAttributeName("readonly")] + public bool? IsReadonly { get; set; } = false; + + public bool AutoFocus { get; set; } + + [HtmlAttributeName("type")] + public string InputTypeName { get; set; } = "text"; + + public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; + + [HtmlAttributeName("required-symbol")] + public bool DisplayRequiredSymbol { get; set; } = true; + + [HtmlAttributeName("asp-format")] + public string Format { get; set; } + + public string Name { get; set; } + + public string Value { get; set; } + + public bool SuppressLabel { get; set; } + + + // Min and Max date + public DateTime? MinDate { get; set; } + + public DateTime? MaxDate { get; set; } + + // Max span between start and end date + public object? MaxSpan { get; set; } + + // Show dropdowns + public bool ShowDropdowns { get; set; } = true; + + // Min and Max year + public int? MinYear { get; set; } + + public int? MaxYear { get; set; } + + // Show week numbers + public AbpDatePickerWeekNumbers WeekNumbers { get; set; } = AbpDatePickerWeekNumbers.None; + + // Time picker + public bool? TimePicker { get; set; } + + // Time picker increment + public int? TimePickerIncrement { get; set; } + + // Time picker 24 hour + public bool? TimePicker24Hour { get; set; } + + // Time picker seconds + public bool? TimePickerSeconds { get; set; } + + // Ranges object + public List Ranges { get; set; } + + // Show custom range label + public bool ShowCustomRangeLabel { get; set; } = true; + + // Always show calendar + public bool AlwaysShowCalendars { get; set; } = false; + + // Opens date picker on left or right or center of the input + public AbpDatePickerOpens Opens { get; set; } = AbpDatePickerOpens.Center; + + // Drops down or up or auto + public AbpDatePickerDrops Drops { get; set; } = AbpDatePickerDrops.Down; + + // Button classes + [CanBeNull] + public string ButtonClasses { get; set; } + + // Apply class to all buttons + [CanBeNull] + public string ApplyButtonClasses { get; set; } + + // Cancel class to all buttons + [CanBeNull] + public string CancelButtonClasses { get; set; } + + // Locale + [CanBeNull] + public object Locale { get; set; } + + // Auto apply + public bool AutoApply { get; set; } = true; + + // Linked calendars + public bool? LinkedCalendars { get; set; } + + // Auto update input + public bool AutoUpdateInput { get; set; } = false; + + // Parent element + [CanBeNull] + public string ParentEl { get; set; } + + // public DatePickerType Type { get; set; } = DatePickerType.Date; + + [CanBeNull] + public string DateFormat { get; set; } + + public bool OpenButton { get; set; } = true; + + public bool ClearButton { get; set; } = true; + + public bool IsUtc { get; set; } = false; + + public bool IsIso { get; set; } = false; + + [CanBeNull] + public object Options { get; set; } + + protected AbpDatePickerBaseTagHelper(AbpDatePickerBaseTagHelperService service) : base(service) + { + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs new file mode 100644 index 0000000000..d3a0026759 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -0,0 +1,643 @@ +using System; +using System.Collections.Generic; +using System.ComponentModel.DataAnnotations; +using System.Linq; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.DependencyInjection; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; +using Volo.Abp.Json; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelperService + where TTagHelper : AbpDatePickerBaseTagHelper +{ + protected readonly Dictionary> SupportedInputTypes = new() { + {typeof(string), o => DateTime.Parse((string)o).ToString("O")}, + {typeof(DateTime), o => ((DateTime) o).ToString("O")}, + {typeof(DateTime?), o => ((DateTime?) o)?.ToString("O")}, + {typeof(DateTimeOffset), o => ((DateTimeOffset) o).ToString("O")}, + {typeof(DateTimeOffset?), o => ((DateTimeOffset?) o)?.ToString("O")} + }; + + protected readonly IJsonSerializer JsonSerializer; + protected readonly IHtmlGenerator Generator; + protected readonly HtmlEncoder Encoder; + protected readonly IServiceProvider ServiceProvider; + protected readonly IAbpTagHelperLocalizer TagHelperLocalizer; + protected virtual string TagName { get; set; } = "abp-date-picker"; + protected IStringLocalizer L { get; } + protected InputTagHelper InputTagHelper { get; set; } + protected abstract TagHelperOutput TagHelperOutput { get; set; } + + protected AbpDatePickerBaseTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, + HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, + IAbpTagHelperLocalizer tagHelperLocalizer) + { + JsonSerializer = jsonSerializer; + Generator = generator; + Encoder = encoder; + ServiceProvider = serviceProvider; + L = l; + TagHelperLocalizer = tagHelperLocalizer; + + InputTagHelper = new InputTagHelper(Generator) { InputTypeName = "text" }; + } + + protected virtual T GetAttribute() where T : Attribute + { + return GetAttributeAndModelExpression(out _); + } + + protected abstract T GetAttributeAndModelExpression(out ModelExpression modelExpression) where T : Attribute; + + + public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + TagHelperOutput = new TagHelperOutput("input", GetInputAttributes(context, output), (_, _) => Task.FromResult(new DefaultTagHelperContent())); + + InputTagHelper.ViewContext = TagHelper.ViewContext; + + if (!TagHelper.Name.IsNullOrEmpty()) + { + InputTagHelper.Name = TagHelper.Name; + } + + if (!TagHelper.Value.IsNullOrEmpty()) + { + InputTagHelper.Value = TagHelper.Value; + } + + AddDisabledAttribute(TagHelperOutput); + AddAutoFocusAttribute(TagHelperOutput); + AddFormControls(context, output, TagHelperOutput); + AddPlaceholderAttribute(TagHelperOutput); + AddInfoTextId(TagHelperOutput); + + // Open and close button + var openButtonContent = TagHelper.OpenButton + ? await ProcessButtonAndGetContentAsync(context, output, "calendar", "open") + : ""; + var clearButtonContent = TagHelper.ClearButton + ? await ProcessButtonAndGetContentAsync(context, output, "times", "clear") + : ""; + + var labelContent = TagHelper.SuppressLabel ? "" : await GetLabelAsHtmlAsync(context, output, TagHelperOutput); + var infoContent = GetInfoAsHtml(context, output, TagHelperOutput); + var validationContent = await GetValidationAsHtmlAsync(context, output); + + var inputGroup = new TagHelperOutput("div", + new TagHelperAttributeList(new[] { new TagHelperAttribute("class", "input-group") }), + (_, _) => Task.FromResult(new DefaultTagHelperContent())); + inputGroup.Content.AppendHtml( + TagHelperOutput.Render(Encoder) + openButtonContent + clearButtonContent + infoContent + ); + + var abpDatePickerTag = new TagHelperOutput(TagName, GetBaseTagAttributes(context, output), + (_, _) => Task.FromResult(new DefaultTagHelperContent())); + abpDatePickerTag.Content.AppendHtml(inputGroup.Render(Encoder)); + abpDatePickerTag.Content.AppendHtml(validationContent); + abpDatePickerTag.Content.AppendHtml(GetExtraInputHtml(context, output)); + + var innerHtml = labelContent + abpDatePickerTag.Render(Encoder); + + var order = GetOrder(); + + AddGroupToFormGroupContents( + context, + GetPropertyName(), + SurroundInnerHtmlAndGet(context, output, innerHtml), + order + ); + + + output.TagMode = TagMode.StartTagAndEndTag; + output.TagName = "div"; + LeaveOnlyGroupAttributes(context, output); + output.Attributes.AddClass("mb-3"); + + output.Content.AppendHtml(innerHtml); + } + + protected virtual TagHelperAttributeList GetInputAttributes(TagHelperContext context, TagHelperOutput output) + { + var groupPrefix = "group-"; + + var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); + + var attrList = new TagHelperAttributeList(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + attrList.Add(tagHelperAttribute); + } + + attrList.Add("type", "text"); + + if (attrList.ContainsName("value")) + { + attrList.Remove(attrList.First(a => a.Name == "value")); + } + + if (!TagHelper.Name.IsNullOrEmpty() && !attrList.ContainsName("name")) + { + attrList.Add("name", TagHelper.Name); + } + + if (!attrList.ContainsName("autocomplete")) + { + attrList.Add("autocomplete", "off"); + } + + return attrList; + } + protected virtual void LeaveOnlyGroupAttributes(TagHelperContext context, TagHelperOutput output) + { + var groupPrefix = "group-"; + var tagHelperAttributes = output.Attributes.Where(a => a.Name.StartsWith(groupPrefix)).ToList(); + + output.Attributes.Clear(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + var nameWithoutPrefix = tagHelperAttribute.Name.Substring(groupPrefix.Length); + var newAttribute = new TagHelperAttribute(nameWithoutPrefix, tagHelperAttribute.Value); + output.Attributes.Add(newAttribute); + } + } + + protected virtual string SurroundInnerHtmlAndGet(TagHelperContext context, TagHelperOutput output, string innerHtml) + { + return "
" + + Environment.NewLine + innerHtml + Environment.NewLine + + "
"; + } + + protected abstract string GetPropertyName(); + + protected virtual void AddGroupToFormGroupContents(TagHelperContext context, string propertyName, string html, + int order) + { + var list = context.GetValue>(FormGroupContents) ?? new List(); + + if (!list.Any(igc => igc.HtmlContent.Contains("id=\"" + propertyName.Replace('.', '_') + "\""))) + { + list.Add(new FormGroupItem { HtmlContent = html, Order = order, PropertyName = propertyName }); + } + } + + protected abstract int GetOrder(); + protected abstract void AddBaseTagAttributes(TagHelperAttributeList attributes); + + protected virtual string GetExtraInputHtml(TagHelperContext context, TagHelperOutput output) + { + return string.Empty; + } + + protected TagHelperAttributeList GetBaseTagAttributes(TagHelperContext context, TagHelperOutput output) + { + var groupPrefix = "group-"; + + var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); + + var attrList = new TagHelperAttributeList(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + attrList.Add(tagHelperAttribute); + } + + if (attrList.ContainsName("type")) + { + attrList.Remove(attrList.First(a => a.Name == "type")); + } + + if (attrList.ContainsName("name")) + { + attrList.Remove(attrList.First(a => a.Name == "name")); + } + + if (attrList.ContainsName("id")) + { + attrList.Remove(attrList.First(a => a.Name == "id")); + } + + if (attrList.ContainsName("value")) + { + attrList.Remove(attrList.First(a => a.Name == "value")); + } + + if (TagHelper.Locale != null) + { + attrList.Add("data-locale", JsonSerializer.Serialize(TagHelper.Locale)); + } + + if (TagHelper.MinDate != null) + { + attrList.Add("data-min-date", TagHelper.MinDate); + } + + if (TagHelper.MaxDate != null) + { + attrList.Add("data-max-date", TagHelper.MaxDate); + } + + if (TagHelper.MaxSpan != null) + { + attrList.Add("data-max-span", JsonSerializer.Serialize(TagHelper.MaxSpan)); + } + + if (TagHelper.ShowDropdowns == false) + { + attrList.Add("data-show-dropdowns", TagHelper.ShowDropdowns.ToString().ToLowerInvariant()); + } + + if (TagHelper.MinYear != null) + { + attrList.Add("data-min-year", TagHelper.MinYear); + } + + if (TagHelper.MaxYear != null) + { + attrList.Add("data-max-year", TagHelper.MaxYear); + } + + switch (TagHelper.WeekNumbers) + { + case AbpDatePickerWeekNumbers.Normal: + attrList.Add("data-show-week-numbers", "true"); + break; + case AbpDatePickerWeekNumbers.Iso: + attrList.Add("data-show-iso-week-numbers", "true"); + break; + } + + if (TagHelper.TimePicker != null) + { + attrList.Add("data-time-picker", TagHelper.TimePicker.ToString().ToLowerInvariant()); + } + + if (TagHelper.TimePickerIncrement != null) + { + attrList.Add("data-time-picker-increment", TagHelper.TimePickerIncrement); + } + + if (TagHelper.TimePicker24Hour != null) + { + attrList.Add("data-time-picker24-hour", TagHelper.TimePicker24Hour.ToString().ToLowerInvariant()); + } + + if (TagHelper.TimePickerSeconds != null) + { + attrList.Add("data-time-picker-seconds", TagHelper.TimePickerSeconds.ToString().ToLowerInvariant()); + } + + if (TagHelper.Opens != AbpDatePickerOpens.Center) + { + attrList.Add("data-opens", TagHelper.Opens.ToString().ToLowerInvariant()); + } + + if (TagHelper.Drops != AbpDatePickerDrops.Down) + { + attrList.Add("data-drops", TagHelper.Drops.ToString().ToLowerInvariant()); + } + + if (!TagHelper.ButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-button-classes", TagHelper.ButtonClasses); + } + + if (!TagHelper.ApplyButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-apply-button-classes", TagHelper.ApplyButtonClasses); + } + + if (!TagHelper.CancelButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-cancel-button-classes", TagHelper.CancelButtonClasses); + } + + if (!TagHelper.AutoApply) + { + attrList.Add("data-auto-apply", TagHelper.AutoApply.ToString().ToLowerInvariant()); + } + + if (TagHelper.LinkedCalendars != null) + { + attrList.Add("data-linked-calendars", TagHelper.LinkedCalendars.ToString().ToLowerInvariant()); + } + + if (TagHelper.AutoUpdateInput) + { + attrList.Add("data-auto-update-input", TagHelper.AutoUpdateInput.ToString().ToLowerInvariant()); + } + + if (!TagHelper.ParentEl.IsNullOrEmpty()) + { + attrList.Add("data-parent-el", TagHelper.ParentEl); + } + + if (!TagHelper.DateFormat.IsNullOrEmpty()) + { + attrList.Add("data-date-format", TagHelper.DateFormat); + } + + if(TagHelper.Ranges != null && TagHelper.Ranges.Any()) + { + var ranges = TagHelper.Ranges.ToDictionary(r => r.Label, r => r.Dates); + + attrList.Add("data-ranges", JsonSerializer.Serialize(ranges)); + } + + if(TagHelper.AlwaysShowCalendars) + { + attrList.Add("data-always-show-calendars", TagHelper.AlwaysShowCalendars.ToString().ToLowerInvariant()); + } + + if(TagHelper.ShowCustomRangeLabel == false) + { + attrList.Add("data-show-custom-range-label", TagHelper.ShowCustomRangeLabel.ToString().ToLowerInvariant()); + } + + if(TagHelper.Options != null) + { + attrList.Add("data-options", JsonSerializer.Serialize(TagHelper.Options)); + } + + if (TagHelper.IsUtc) + { + attrList.Add("data-is-utc", "true"); + } + + if (TagHelper.IsIso) + { + attrList.Add("data-is-iso", TagHelper.IsIso.ToString().ToLowerInvariant()); + } + + AddBaseTagAttributes(attrList); + + return attrList; + } + + protected virtual bool IsOutputHidden(TagHelperOutput inputTag) + { + return inputTag.Attributes.Any(a => + a.Name.ToLowerInvariant() == "type" && a.Value?.ToString()?.ToLowerInvariant() == "hidden"); + } + + protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) + { + if (IsOutputHidden(inputTag)) + { + return string.Empty; + } + + string text; + ModelExplorer modelExplorer = null; + + if (!string.IsNullOrEmpty(TagHelper.InfoText)) + { + text = TagHelper.InfoText; + } + else + { + var infoAttribute = GetAttributeAndModelExpression(out var modelExpression); + if (infoAttribute != null) + { + modelExplorer = modelExpression.ModelExplorer; + text = infoAttribute.Text; + } + else + { + return string.Empty; + } + } + + var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + var localizedText = TagHelperLocalizer.GetLocalizedText(text, modelExplorer); + + var div = new TagBuilder("div"); + div.Attributes.Add("id", idAttr?.Value + "InfoText"); + div.AddCssClass("form-text"); + div.InnerHtml.Append(localizedText); + + inputTag.Attributes.Add("aria-describedby", idAttr?.Value + "InfoText"); + + return div.ToHtmlString(); + } + + protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, + TagHelperOutput inputTag) + { + if (string.IsNullOrEmpty(TagHelper.Label)) + { + return await GetLabelAsHtmlUsingTagHelperAsync(context, output) + GetRequiredSymbol(context, output); + } + + var label = new TagBuilder("label"); + label.Attributes.Add("for", GetIdAttributeValue(inputTag)); + label.InnerHtml.AppendHtml(TagHelper.Label); + + label.AddCssClass("form-label"); + + if (!TagHelper.LabelTooltip.IsNullOrEmpty()) + { + label.Attributes.Add("data-bs-toggle", "tooltip"); + label.Attributes.Add("data-bs-placement", TagHelper.LabelTooltipPlacement); + if (TagHelper.LabelTooltipHtml) + { + label.Attributes.Add("data-bs-html", "true"); + } + + label.Attributes.Add("title", TagHelper.LabelTooltip); + label.InnerHtml.AppendHtml($" "); + } + + return label.ToHtmlString(); + } + + protected virtual string GetIdAttributeValue(TagHelperOutput inputTag) + { + var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + + return idAttr != null ? idAttr.Value.ToString() : string.Empty; + } + + protected virtual string GetRequiredSymbol(TagHelperContext context, TagHelperOutput output) + { + if (!TagHelper.DisplayRequiredSymbol) + { + return ""; + } + + return GetAttribute() != null ? " * " : ""; + } + + protected abstract ModelExpression GetModelExpression(); + + protected virtual async Task GetLabelAsHtmlUsingTagHelperAsync(TagHelperContext context, + TagHelperOutput output) + { + var labelTagHelper = new LabelTagHelper(Generator) { + ViewContext = TagHelper.ViewContext, + For = GetModelExpression() + }; + + var attributeList = new TagHelperAttributeList(); + + attributeList.AddClass("form-label"); + + if (!TagHelper.LabelTooltip.IsNullOrEmpty()) + { + attributeList.Add("data-bs-toggle", "tooltip"); + attributeList.Add("data-bs-placement", TagHelper.LabelTooltipPlacement); + if (TagHelper.LabelTooltipHtml) + { + attributeList.Add("data-bs-html", "true"); + } + + attributeList.Add("title", TagHelper.LabelTooltip); + } + + var innerOutput = + await labelTagHelper.ProcessAndGetOutputAsync(attributeList, context, "label", TagMode.StartTagAndEndTag); + if (!TagHelper.LabelTooltip.IsNullOrEmpty()) + { + innerOutput.Content.AppendHtml($" "); + } + + return innerOutput.Render(Encoder); + } + + protected virtual async Task ProcessButtonAndGetContentAsync(TagHelperContext context, + TagHelperOutput output, string icon, string type) + { + var abpButtonTagHelper = ServiceProvider.GetRequiredService(); + var attributes = + new TagHelperAttributeList { new("type", "button"), new("tabindex", "-1"), new("data-type", type) }; + abpButtonTagHelper.ButtonType = AbpButtonType.Outline_Secondary; + abpButtonTagHelper.Icon = icon; + + return await abpButtonTagHelper.RenderAsync(attributes, context, Encoder, "button", TagMode.StartTagAndEndTag); + } + + protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) + { + if (GetAttribute() == null) + { + return; + } + + var idAttr = inputTagHelperOutput.Attributes.FirstOrDefault(a => a.Name == "id"); + + if (idAttr == null) + { + return; + } + + inputTagHelperOutput.Attributes.Add("aria-describedby", GetInfoText()); + } + + public virtual string GetInfoText() + { + var infoAttribute = GetAttributeAndModelExpression(out var modelExpression); + + if (infoAttribute != null) + { + return TagHelperLocalizer.GetLocalizedText(infoAttribute.Text, modelExpression.ModelExplorer); + } + + return string.Empty; + } + + protected virtual void AddPlaceholderAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("placeholder")) + { + return; + } + + var attribute = GetAttributeAndModelExpression(out var modelExpression); + + if (attribute != null) + { + var placeholderLocalized = + TagHelperLocalizer.GetLocalizedText(attribute.Value, modelExpression.ModelExplorer); + + inputTagHelperOutput.Attributes.Add("placeholder", placeholderLocalized); + } + } + + protected virtual void AddFormControls(TagHelperContext context, TagHelperOutput output, + TagHelperOutput inputTagHelperOutput) + { + inputTagHelperOutput.Attributes.AddClass("form-control"); + var size = GetSize(context, output); + if (!size.IsNullOrEmpty()) + { + inputTagHelperOutput.Attributes.AddClass(size); + } + } + + protected virtual void AddAutoFocusAttribute(TagHelperOutput inputTagHelperOutput) + { + if (TagHelper.AutoFocus && !inputTagHelperOutput.Attributes.ContainsName("data-auto-focus")) + { + inputTagHelperOutput.Attributes.Add("data-auto-focus", "true"); + } + } + + protected virtual void AddDisabledAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("disabled") == false && + (TagHelper.IsDisabled || GetAttribute() != null)) + { + inputTagHelperOutput.Attributes.Add("disabled", ""); + } + } + + + protected virtual string GetSize(TagHelperContext context, TagHelperOutput output) + { + // TODO: Test this method + var attribute = GetAttribute(); + + if (attribute != null) + { + TagHelper.Size = attribute.Size; + } + + return TagHelper.Size switch { + AbpFormControlSize.Small => "form-control-sm", + AbpFormControlSize.Medium => "form-control-md", + AbpFormControlSize.Large => "form-control-lg", + _ => "" + }; + } + + protected abstract Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output); + + protected virtual async Task GetValidationAsHtmlByInputAsync(TagHelperContext context, + TagHelperOutput output, + [NotNull]InputTagHelper inputTag) + { + var validationMessageTagHelper = + new ValidationMessageTagHelper(Generator) { For = inputTag.For, ViewContext = TagHelper.ViewContext }; + + var attributeList = new TagHelperAttributeList { { "class", "text-danger col-auto" } }; + + return await validationMessageTagHelper.RenderAsync(attributeList, context, Encoder, "span", + TagMode.StartTagAndEndTag); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs new file mode 100644 index 0000000000..72e2e663ca --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +public enum AbpDatePickerDrops +{ + Down, + Up, + Auto +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs new file mode 100644 index 0000000000..f499f9ce51 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +public enum AbpDatePickerOpens +{ + Left, + Right, + Center +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs new file mode 100644 index 0000000000..8643668283 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs @@ -0,0 +1,47 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +public class AbpDatePickerRange +{ + private readonly List _dates = new List(); + public string Label { get; set; } + public IReadOnlyList Dates => _dates; + + public void AddDate(string date) + { + _dates.Add(DateTime.Parse(date).ToString("O")); + } + + public void AddDate(DateTime date) + { + _dates.Add(date.ToString("O")); + } + + public void AddDate(DateTimeOffset date) + { + _dates.Add(date.ToString("O")); + } + + public void AddDate(DateTime? date) + { + if (date.HasValue) + { + _dates.Add(date.Value.ToString("O")); + } + } + + public void AddDate(DateTimeOffset? date) + { + if (date.HasValue) + { + _dates.Add(date.Value.ToString("O")); + } + } + + public void AddDate(string date, string format) + { + _dates.Add(DateTime.ParseExact(date, format, null).ToString("O")); + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs new file mode 100644 index 0000000000..e328f89205 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +public enum AbpDatePickerWeekNumbers +{ + None, + Normal, + Iso +} \ No newline at end of file From d7d4c0cc3ca41729db0120dbd8d84180d21ac92e Mon Sep 17 00:00:00 2001 From: Salih Date: Sun, 19 Feb 2023 18:12:58 +0300 Subject: [PATCH 02/28] Create AbpDateRangePicker.cs --- .../DatePicker/AbpDateRangePicker.cs | 146 ++++++++++++++++++ 1 file changed, 146 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs new file mode 100644 index 0000000000..9f88e2f5a3 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs @@ -0,0 +1,146 @@ +using System; +using System.Linq; +using System.Text; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.Json; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +[HtmlTargetElement("abp-date-range-picker", TagStructure = TagStructure.NormalOrSelfClosing)] +public class AbpDateRangePickerTagHelper : AbpDatePickerBaseTagHelper +{ + // Start date + [CanBeNull] + public ModelExpression AspForStart { get; set; } + + // End date + [CanBeNull] + public ModelExpression AspForEnd { get; set; } + + public AbpDateRangePickerTagHelper(AbpDateRangePickerTagHelperService tagHelperService) : base(tagHelperService) + { + } +} + +public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperService +{ + public AbpDateRangePickerTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, + HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, + IAbpTagHelperLocalizer tagHelperLocalizer) : base(jsonSerializer, generator, encoder, serviceProvider, l, + tagHelperLocalizer) + { + } + + protected override string TagName { get; set; } = "abp-date-range-picker"; + + protected override T GetAttributeAndModelExpression(out ModelExpression modelExpression) + { + modelExpression = + new[] { TagHelper.AspForStart, TagHelper.AspForEnd }.FirstOrDefault(x => + x?.ModelExplorer?.GetAttribute() != null); + return modelExpression?.ModelExplorer.GetAttribute(); + } + + public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + + if (TagHelper.AspForStart != null) + { + var startDateAttributes = + new TagHelperAttributeList { { "data-start-date", "true" }, { "type", "hidden" } }; + StartDateTagHelper = new InputTagHelper(Generator) { + ViewContext = TagHelper.ViewContext, For = TagHelper.AspForStart, InputTypeName = "hidden" + }; + + StartDateTagHelperOutput = + await StartDateTagHelper.ProcessAndGetOutputAsync(startDateAttributes, context, "input"); + } + + if (TagHelper.AspForEnd != null) + { + var endDateAttributes = new TagHelperAttributeList { { "data-end-date", "true" }, { "type", "hidden" } }; + EndDateTagHelper = new InputTagHelper(Generator) { + ViewContext = TagHelper.ViewContext, For = TagHelper.AspForEnd,InputTypeName = "hidden" + }; + + EndDateTagHelperOutput = + await EndDateTagHelper.ProcessAndGetOutputAsync(endDateAttributes, context, "input"); + } + + await base.ProcessAsync(context, output); + } + + protected override TagHelperOutput TagHelperOutput { get; set; } + + [CanBeNull] + protected virtual InputTagHelper StartDateTagHelper { get; set; } + + [CanBeNull] + protected virtual TagHelperOutput StartDateTagHelperOutput { get; set; } + + [CanBeNull] + protected virtual InputTagHelper EndDateTagHelper { get; set; } + + [CanBeNull] + protected virtual TagHelperOutput EndDateTagHelperOutput { get; set; } + + protected override string GetPropertyName() + { + return TagHelper.AspForStart?.Name ?? string.Empty; + } + + protected override int GetOrder() + { + return TagHelper.Order; + } + + protected override void AddBaseTagAttributes(TagHelperAttributeList attributes) + { + if (TagHelper.AspForStart != null && TagHelper.AspForStart.Model != null && + SupportedInputTypes.TryGetValue(TagHelper.AspForStart.Metadata.ModelType, out var convertFuncStart)) + { + attributes.Add("data-start-date", convertFuncStart(TagHelper.AspForStart.Model)); + } + + if (TagHelper.AspForEnd != null && TagHelper.AspForEnd.Model != null && + SupportedInputTypes.TryGetValue(TagHelper.AspForEnd.Metadata.ModelType, out var convertFuncEnd)) + { + attributes.Add("data-end-date", convertFuncEnd(TagHelper.AspForEnd.Model)); + } + } + + protected override string GetExtraInputHtml(TagHelperContext context, TagHelperOutput output) + { + return StartDateTagHelperOutput?.Render(Encoder) + EndDateTagHelperOutput?.Render(Encoder); + } + + protected override ModelExpression GetModelExpression() + { + return TagHelper.AspForStart; + } + + protected async override Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output) + { + var validationHtml = string.Empty; + + if (StartDateTagHelper != null) + { + validationHtml += await GetValidationAsHtmlByInputAsync(context, output, StartDateTagHelper); + } + + if (EndDateTagHelper != null) + { + validationHtml += await GetValidationAsHtmlByInputAsync(context, output, EndDateTagHelper); + } + + return validationHtml; + } +} \ No newline at end of file From c4b9c1c2366167dcba6fe52923704e38353c2c24 Mon Sep 17 00:00:00 2001 From: Salih Date: Sun, 19 Feb 2023 18:13:01 +0300 Subject: [PATCH 03/28] Create AbpDatePickerTag.cs --- .../TagHelpers/DatePicker/AbpDatePickerTag.cs | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs new file mode 100644 index 0000000000..a368037451 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs @@ -0,0 +1,96 @@ +using System; +using System.Text.Encodings.Web; +using System.Threading.Tasks; +using JetBrains.Annotations; +using Localization.Resources.AbpUi; +using Microsoft.AspNetCore.Mvc.TagHelpers; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.Extensions.Localization; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.Json; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; + +[HtmlTargetElement("abp-date-picker", TagStructure = TagStructure.NormalOrSelfClosing)] +public class AbpDatePickerTagHelper : AbpDatePickerBaseTagHelper +{ + [CanBeNull] + public ModelExpression AspFor { get; set; } + + public AbpDatePickerTagHelper(AbpDatePickerTagHelperService service) : base(service) + { + } +} + + + +public class AbpDatePickerTagHelperService : AbpDatePickerBaseTagHelperService +{ + public AbpDatePickerTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, IAbpTagHelperLocalizer tagHelperLocalizer) : base(jsonSerializer, generator, encoder, serviceProvider, l, tagHelperLocalizer) + { + + } + + protected override TagHelperOutput TagHelperOutput { get; set; } + + [CanBeNull] + protected virtual InputTagHelper DateTagHelper { get; set; } + + [CanBeNull] + protected virtual TagHelperOutput DateTagHelperOutput { get; set; } + protected override string GetPropertyName() + { + return TagHelper.AspFor?.Name ?? string.Empty; + } + + protected override T GetAttributeAndModelExpression(out ModelExpression modelExpression) + { + modelExpression = TagHelper.AspFor; + return modelExpression?.ModelExplorer.GetAttribute(); + } + + public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) + { + + if(TagHelper.AspFor != null) + { + DateTagHelper = new InputTagHelper(Generator) { + InputTypeName = "hidden", ViewContext = TagHelper.ViewContext, For = TagHelper.AspFor, + }; + var attributes = new TagHelperAttributeList { { "data-date", "true" }, { "type", "hidden" } }; + DateTagHelperOutput = await DateTagHelper.ProcessAndGetOutputAsync(attributes, context, "input"); + } + + await base.ProcessAsync(context, output); + } + + + protected override int GetOrder() + { + return TagHelper.AspFor?.Metadata.Order ?? 0; + } + + protected override void AddBaseTagAttributes(TagHelperAttributeList attributes) + { + if(TagHelper.AspFor != null && TagHelper.AspFor.Model != null && SupportedInputTypes.TryGetValue(TagHelper.AspFor.Metadata.ModelType, out var convertFunc)) + { + attributes.Add("data-date", convertFunc(TagHelper.AspFor.Model)); + } + } + + protected override ModelExpression GetModelExpression() + { + return TagHelper.AspFor; + } + + protected async override Task GetValidationAsHtmlAsync(TagHelperContext context, TagHelperOutput output) + { + return DateTagHelper != null ? await GetValidationAsHtmlByInputAsync(context, output, DateTagHelper) : string.Empty; + } + + protected override string GetExtraInputHtml(TagHelperContext context, TagHelperOutput output) + { + return DateTagHelperOutput?.Render(Encoder); + } +} \ No newline at end of file From 77a4f2fc0254cb4b407507c79c0dee66d8cb9ce2 Mon Sep 17 00:00:00 2001 From: Salih Date: Sun, 19 Feb 2023 18:13:30 +0300 Subject: [PATCH 04/28] Added initializeDateRangePickers method --- .../bootstrap/dom-event-handlers.js | 376 ++++++++++++++++++ 1 file changed, 376 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index d1cbfa6b6b..acbb0908e9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -187,6 +187,381 @@ }); }); } + + abp.libs.bootstrapDateRangePicker = { + packageName: "bootstrap-daterangepicker", + + createDateRangePicker: function (options) { + options = options || {}; + options.singleDatePicker = false; + return this.createDatePicker(options); + }, + createSinglePicker: function (options) { + options = options || {}; + options.singleDatePicker = true; + return this.createDatePicker(options); + }, + createDatePicker: function (options) { + var $container = $('
') + var label = $('') + if (options.label) { + label.text(options.label) + } + $container.append(label) + var $datePicker = options.singleDatePicker ? $('') : $(''); + $container.append($datePicker) + + var $inputGroup = $('
'); + var $dateInput = $(''); + + if (options.placeholder) { + $dateInput.attr('placeholder', options.placeholder) + } + + if (options.value) { + $dateInput.val(options.value) + } + + if (options.name) { + $dateInput.attr('name', options.name) + } + + if (options.id) { + $dateInput.attr('id', options.id) + } + + if (options.required) { + $dateInput.attr('required', true) + } + + if (options.disabled) { + $dateInput.attr('disabled', true) + } + + if (options.readonly) { + $dateInput.attr('readonly', true) + } + + if (options.size) { + switch (options.size) { + case 'Small': + $dateInput.addClass('form-control-sm') + break; + case 'Medium': + $dateInput.addClass('form-control-md') + break; + case 'Large': + $dateInput.addClass('form-control-lg') + break; + default: + break; + } + } + + $inputGroup.append($dateInput); + + if (options.openButton !== false) { + var $openButton = $(''); + $inputGroup.append($openButton); + } + + if (options.clearButton !== false) { + var $clearButton = $(''); + $inputGroup.append($clearButton); + } + + $datePicker.append($inputGroup); + + if (options.startDateName) { + var $hiddenStartDateElement = $(''); + $datePicker.append($hiddenStartDateElement); + } + + if (options.endDateName) { + var $hiddenEndDateElement = $(''); + $datePicker.append($hiddenEndDateElement); + } + + if (options.dateName) { + var $hiddenDateElement = $(''); + $datePicker.append($hiddenDateElement); + } + + $container.data('options', options); + if($container.data('options', options)){ + debugger; + } + abp.dom.initializers.initializeDateRangePickers($container); + return $container; + } + }; + + + abp.dom.initializers.initializeDateRangePickers = function ($rootElement) { + $rootElement + .findWithSelf('abp-date-picker,abp-date-range-picker') + .each(function () { + var $this = $(this); + var $input = $(this).find('.input-group input[type="text"]') + if($input.data('daterangepicker')) { + return; + } + var $openButton = $(this).find('button[data-type="open"]') + var $clearButton = $(this).find('button[data-type="clear"]') + var singleDatePicker = $this.is('abp-date-picker') + var options = {}; + + var defaultOptions = { + showDropdowns: true, + opens: "center", + drops: "down", + autoApply: true, + autoUpdateInput: false + }; + + $.extend(options, defaultOptions); + $.extend(options, $this.data()); + if($this.data("options")){ + debugger; + $.extend(options, $this.data("options")); + } + $.extend(options, $this.data("options")); + + var isUtc = options.isUtc; + var isIso = options.isIso; + var timePicker = options.timePicker; + var timePicker24Hour = options.timePicker24Hour; + var timePickerSeconds = options.timePickerSeconds; + var dateFormat = options.dateFormat; + var separator = options.separator; + const getMoment = function (date) { + if(!date){ + return isUtc ? moment.utc() : moment(); + } + if(isUtc) { + return moment.utc(date,dateFormat); + }else { + return moment(date,dateFormat); + } + } + + if (dateFormat) { + options.locale = options.locale || {}; + options.locale.format = dateFormat; + } + + if (separator) { + options.locale = options.locale || {}; + options.locale.separator = separator; + } + + var startDate = options.startDate ? getMoment(options.startDate) : null; + if(singleDatePicker && !startDate){ + startDate = options.date ? getMoment(options.date) : null; + } + var endDate = options.endDate ? getMoment(options.endDate) : null; + + if (startDate) { + options.startDate = startDate; + } + if (endDate) { + options.endDate = endDate; + } + + if(options.ranges){ + $.each(options.ranges, function (key, value) { + let start = value[0]; + let end; + if(value.length > 1){ + end = value[1]; + }else{ + end = value[0]; + } + options.ranges[key] = [getMoment(start), getMoment(end)]; + }); + } + + $input.daterangepicker(options); + var $dateRangePicker = $input.data('daterangepicker'); + + $dateRangePicker.outsideClick = function(e) { + var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button + // itself then call this.hide() + if ( + // ie modal dialog fix + e.type == "focusin" || + target.closest(this.element).length || + target.closest(this.container).length || + target.closest('.calendar-table').length || + target.closest($openButton).length + ) return; + this.hide(); + this.element.trigger('outsideClick.daterangepicker', this); + }; + + $openButton.on('click', function () { + $dateRangePicker.toggle(); + }); + + + if(!dateFormat) { + if(timePicker){ + if(timePicker24Hour){ + if(timePickerSeconds){ + dateFormat = moment.localeData().longDateFormat('L') + " HH:mm:ss"; + }else{ + dateFormat = moment.localeData().longDateFormat('L') + " HH:mm"; + } + }else { + if (timePickerSeconds) { + dateFormat = moment.localeData().longDateFormat('L') + ' ' + " hh:mm:ss A" + } else { + dateFormat = moment.localeData().longDateFormat('L') + " hh:mm A"; + } + } + }else{ + dateFormat = moment.localeData().longDateFormat('L'); + } + } + + + if(!separator) { + separator = $dateRangePicker.locale.separator; + } + + if(singleDatePicker){ + if(startDate){ + $input.val(startDate.format(dateFormat)); + } + }else{ + if(startDate && endDate){ + $input.val(startDate.format(dateFormat) + separator + endDate.format(dateFormat)); + } + } + + $input.on('apply.daterangepicker', function (ev, picker) { + if(singleDatePicker){ + $(this).val(picker.startDate.format(dateFormat)); + }else{ + $(this).val(picker.startDate.format(dateFormat) + separator + picker.endDate.format(dateFormat)); + } + + $(this).trigger('change'); + }); + + $input.on('cancel.daterangepicker', function (ev, picker) { + $(this).val(''); + $(this).trigger('change'); + }); + $input.on('show.daterangepicker', function (ev, picker) { + var momentStartDate = getMoment(startDate); + var momentEndDate = getMoment(endDate); + if (momentStartDate.isValid()) { + picker.setStartDate(momentStartDate); + } + if (momentEndDate.isValid()) { + picker.setEndDate(momentEndDate); + } + }); + + + $clearButton.on('click', function () { + $input.val(''); + $input.trigger('change'); + }); + + $input.on('change', function () { + var dates = $(this).val().split(separator); + if (dates.length === 2) { + startDate = getMoment(dates[0]); + if (!startDate.isValid()) { + startDate = null; + }else{ + startDate = formatDate(startDate); + } + endDate = getMoment(dates[1]); + if (!endDate.isValid()) { + endDate = null; + }else{ + endDate = formatDate(endDate); + } + } else { + startDate = getMoment(dates[0]); + if (!startDate.isValid()) { + startDate = null; + }else{ + startDate = formatDate(startDate); + } + endDate = null; + } + + if(!startDate){ + $dateRangePicker.setStartDate(getMoment()); + $dateRangePicker.setEndDate(getMoment()); + } + + if(!singleDatePicker){ + var input1 = $this.find("input[data-start-date]") + input1.val(startDate); + var input2 = $this.find("input[data-end-date]") + input2.val(endDate); + }else{ + var input = $this.find("input[data-date]") + input.val(startDate); + } + + if(singleDatePicker){ + $this.data('date', startDate); + $input.data('date', startDate); + }else{ + $this.data('startDate', startDate); + $this.data('endDate', endDate); + $input.data('startDate', startDate); + $input.data('endDate', endDate); + } + }); + + function formatDate(date){ + if(date){ + debugger; + if(isIso){ + return date.format(); + } + return date.format(dateFormat) + } + return null; + } + function getFormattedStartDate (){ + if(startDate){ + return getMoment(startDate).format(dateFormat); + } + return null; + } + + function getFormattedEndDate (){ + if(endDate){ + return getMoment(endDate).format(dateFormat); + } + return null; + } + + if(singleDatePicker){ + $this[0].getFormattedDate = getFormattedStartDate; + $input[0].getFormattedDate = getFormattedStartDate; + $dateRangePicker.getFormattedDate = getFormattedStartDate; + }else{ + $dateRangePicker.getFormattedStartDate = getFormattedStartDate; + $dateRangePicker.getFormattedEndDate = getFormattedEndDate; + + $this[0].getFormattedStartDate = getFormattedStartDate; + $this[0].getFormattedEndDate = getFormattedEndDate; + + $input[0].getFormattedStartDate = getFormattedStartDate; + $input[0].getFormattedEndDate = getFormattedEndDate; + } + }); + } abp.dom.onNodeAdded(function (args) { abp.dom.initializers.initializeToolTips(args.$el.findWithSelf('[data-toggle="tooltip"]')); @@ -212,6 +587,7 @@ abp.dom.initializers.initializePopovers($('[data-toggle="popover"]')); abp.dom.initializers.initializeTimeAgos($('.timeago')); abp.dom.initializers.initializeDatepickers($(document)); + abp.dom.initializers.initializeDateRangePickers($(document)); abp.dom.initializers.initializeForms($('form')); abp.dom.initializers.initializeAutocompleteSelects($('.auto-complete-select')); $('[data-auto-focus="true"]').first().findWithSelf('input,select').focus(); From 0f59bca5abd43be27e6f2cf147c13e886f5ea4a8 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Feb 2023 20:39:46 +0300 Subject: [PATCH 05/28] Refactor and add atrributes --- .../DatePicker/AbpDatePickerBaseTagHelper.cs | 147 ------------ .../DatePicker/AbpDatePickerDrops.cs | 8 - .../DatePicker/AbpDatePickerOpens.cs | 8 - .../DatePicker/AbpDatePickerWeekNumbers.cs | 8 - .../DatePicker/AbpDatePickerBaseTagHelper.cs | 208 ++++++++++++++++ .../AbpDatePickerBaseTagHelperService.cs | 223 +++++++++++------- .../Form/DatePicker/AbpDatePickerDrops.cs | 8 + .../Form/DatePicker/AbpDatePickerOpens.cs | 8 + .../Form/DatePicker/AbpDatePickerOptions.cs | 39 +++ .../DatePicker/AbpDatePickerRange.cs | 2 +- .../Form/DatePicker/AbpDatePickerTagHelper.cs | 16 ++ .../AbpDatePickerTagHelperService.cs} | 15 +- .../DatePicker/AbpDatePickerWeekNumbers.cs | 8 + .../DatePicker/AbpDateRangePickerTagHelper.cs | 21 ++ .../AbpDateRangePickerTagHelperService.cs} | 19 +- .../Form/DatePicker/DatePickerAttribute.cs | 8 + .../DatePicker/DatePickerOptionsAttribute.cs | 169 +++++++++++++ .../DatePicker/DateRangePickerAttribute.cs | 16 ++ .../Form/DatePicker/IAbpDatePickerOptions.cs | 100 ++++++++ .../bootstrap/dom-event-handlers.js | 46 ++-- 20 files changed, 764 insertions(+), 313 deletions(-) delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs delete mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs rename framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/{ => Form}/DatePicker/AbpDatePickerBaseTagHelperService.cs (78%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs rename framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/{ => Form}/DatePicker/AbpDatePickerRange.cs (92%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs rename framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/{DatePicker/AbpDatePickerTag.cs => Form/DatePicker/AbpDatePickerTagHelperService.cs} (87%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs rename framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/{DatePicker/AbpDateRangePicker.cs => Form/DatePicker/AbpDateRangePickerTagHelperService.cs} (88%) create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs create mode 100644 framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs deleted file mode 100644 index 5fbe1a2c7e..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelper.cs +++ /dev/null @@ -1,147 +0,0 @@ -using System; -using System.Collections.Generic; -using JetBrains.Annotations; -using Microsoft.AspNetCore.Razor.TagHelpers; -using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; - -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; - -public abstract class - AbpDatePickerBaseTagHelper : AbpTagHelper> - where TTagHelper : AbpDatePickerBaseTagHelper - -{ - public string Label { get; set; } - - public string LabelTooltip { get; set; } - - public string LabelTooltipIcon { get; set; } = "bi-info-circle"; - - public string LabelTooltipPlacement { get; set; } = "right"; - - public bool LabelTooltipHtml { get; set; } = false; - - [HtmlAttributeName("info")] - public string InfoText { get; set; } - - [HtmlAttributeName("disabled")] - public bool IsDisabled { get; set; } = false; - - [HtmlAttributeName("readonly")] - public bool? IsReadonly { get; set; } = false; - - public bool AutoFocus { get; set; } - - [HtmlAttributeName("type")] - public string InputTypeName { get; set; } = "text"; - - public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; - - [HtmlAttributeName("required-symbol")] - public bool DisplayRequiredSymbol { get; set; } = true; - - [HtmlAttributeName("asp-format")] - public string Format { get; set; } - - public string Name { get; set; } - - public string Value { get; set; } - - public bool SuppressLabel { get; set; } - - - // Min and Max date - public DateTime? MinDate { get; set; } - - public DateTime? MaxDate { get; set; } - - // Max span between start and end date - public object? MaxSpan { get; set; } - - // Show dropdowns - public bool ShowDropdowns { get; set; } = true; - - // Min and Max year - public int? MinYear { get; set; } - - public int? MaxYear { get; set; } - - // Show week numbers - public AbpDatePickerWeekNumbers WeekNumbers { get; set; } = AbpDatePickerWeekNumbers.None; - - // Time picker - public bool? TimePicker { get; set; } - - // Time picker increment - public int? TimePickerIncrement { get; set; } - - // Time picker 24 hour - public bool? TimePicker24Hour { get; set; } - - // Time picker seconds - public bool? TimePickerSeconds { get; set; } - - // Ranges object - public List Ranges { get; set; } - - // Show custom range label - public bool ShowCustomRangeLabel { get; set; } = true; - - // Always show calendar - public bool AlwaysShowCalendars { get; set; } = false; - - // Opens date picker on left or right or center of the input - public AbpDatePickerOpens Opens { get; set; } = AbpDatePickerOpens.Center; - - // Drops down or up or auto - public AbpDatePickerDrops Drops { get; set; } = AbpDatePickerDrops.Down; - - // Button classes - [CanBeNull] - public string ButtonClasses { get; set; } - - // Apply class to all buttons - [CanBeNull] - public string ApplyButtonClasses { get; set; } - - // Cancel class to all buttons - [CanBeNull] - public string CancelButtonClasses { get; set; } - - // Locale - [CanBeNull] - public object Locale { get; set; } - - // Auto apply - public bool AutoApply { get; set; } = true; - - // Linked calendars - public bool? LinkedCalendars { get; set; } - - // Auto update input - public bool AutoUpdateInput { get; set; } = false; - - // Parent element - [CanBeNull] - public string ParentEl { get; set; } - - // public DatePickerType Type { get; set; } = DatePickerType.Date; - - [CanBeNull] - public string DateFormat { get; set; } - - public bool OpenButton { get; set; } = true; - - public bool ClearButton { get; set; } = true; - - public bool IsUtc { get; set; } = false; - - public bool IsIso { get; set; } = false; - - [CanBeNull] - public object Options { get; set; } - - protected AbpDatePickerBaseTagHelper(AbpDatePickerBaseTagHelperService service) : base(service) - { - } -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs deleted file mode 100644 index 72e2e663ca..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerDrops.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; - -public enum AbpDatePickerDrops -{ - Down, - Up, - Auto -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs deleted file mode 100644 index f499f9ce51..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerOpens.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; - -public enum AbpDatePickerOpens -{ - Left, - Right, - Center -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs deleted file mode 100644 index e328f89205..0000000000 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerWeekNumbers.cs +++ /dev/null @@ -1,8 +0,0 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; - -public enum AbpDatePickerWeekNumbers -{ - None, - Normal, - Iso -} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs new file mode 100644 index 0000000000..75c3291901 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs @@ -0,0 +1,208 @@ +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public abstract class + AbpDatePickerBaseTagHelper : AbpTagHelper>, IAbpDatePickerOptions + where TTagHelper : AbpDatePickerBaseTagHelper + +{ + private IAbpDatePickerOptions _abpDatePickerOptionsImplementation; + public string Label { get; set; } + + public string LabelTooltip { get; set; } + + public string LabelTooltipIcon { get; set; } = "bi-info-circle"; + + public string LabelTooltipPlacement { get; set; } = "right"; + + public bool LabelTooltipHtml { get; set; } = false; + + [HtmlAttributeName("info")] + public string InfoText { get; set; } + + [HtmlAttributeName("disabled")] + public bool IsDisabled { get; set; } = false; + + [HtmlAttributeName("readonly")] + public bool? IsReadonly { get; set; } = false; + + public bool AutoFocus { get; set; } + + public AbpFormControlSize Size { get; set; } = AbpFormControlSize.Default; + + [HtmlAttributeName("required-symbol")] + public bool DisplayRequiredSymbol { get; set; } = true; + + public string Name { get; set; } + + public string Value { get; set; } + + public bool SuppressLabel { get; set; } + + + + + protected AbpDatePickerBaseTagHelper(AbpDatePickerBaseTagHelperService service) : base(service) + { + _abpDatePickerOptionsImplementation = new AbpDatePickerOptions(); + } + + + public string PickerId { + get => _abpDatePickerOptionsImplementation.PickerId; + set => _abpDatePickerOptionsImplementation.PickerId = value; + } + + public DateTime? MinDate { + get => _abpDatePickerOptionsImplementation.MinDate; + set => _abpDatePickerOptionsImplementation.MinDate = value; + } + + public DateTime? MaxDate { + get => _abpDatePickerOptionsImplementation.MaxDate; + set => _abpDatePickerOptionsImplementation.MaxDate = value; + } + + public object MaxSpan { + get => _abpDatePickerOptionsImplementation.MaxSpan; + set => _abpDatePickerOptionsImplementation.MaxSpan = value; + } + + public bool? ShowDropdowns { + get => _abpDatePickerOptionsImplementation.ShowDropdowns; + set => _abpDatePickerOptionsImplementation.ShowDropdowns = value; + } + + public int? MinYear { + get => _abpDatePickerOptionsImplementation.MinYear; + set => _abpDatePickerOptionsImplementation.MinYear = value; + } + + public int? MaxYear { + get => _abpDatePickerOptionsImplementation.MaxYear; + set => _abpDatePickerOptionsImplementation.MaxYear = value; + } + + public AbpDatePickerWeekNumbers WeekNumbers { + get => _abpDatePickerOptionsImplementation.WeekNumbers; + set => _abpDatePickerOptionsImplementation.WeekNumbers = value; + } + + public bool? TimePicker { + get => _abpDatePickerOptionsImplementation.TimePicker; + set => _abpDatePickerOptionsImplementation.TimePicker = value; + } + + public int? TimePickerIncrement { + get => _abpDatePickerOptionsImplementation.TimePickerIncrement; + set => _abpDatePickerOptionsImplementation.TimePickerIncrement = value; + } + + public bool? TimePicker24Hour { + get => _abpDatePickerOptionsImplementation.TimePicker24Hour; + set => _abpDatePickerOptionsImplementation.TimePicker24Hour = value; + } + + public bool? TimePickerSeconds { + get => _abpDatePickerOptionsImplementation.TimePickerSeconds; + set => _abpDatePickerOptionsImplementation.TimePickerSeconds = value; + } + + public List Ranges { + get => _abpDatePickerOptionsImplementation.Ranges; + set => _abpDatePickerOptionsImplementation.Ranges = value; + } + + public bool? ShowCustomRangeLabel { + get => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel; + set => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel = value; + } + + public bool? AlwaysShowCalendars { + get => _abpDatePickerOptionsImplementation.AlwaysShowCalendars; + set => _abpDatePickerOptionsImplementation.AlwaysShowCalendars = value; + } + + public AbpDatePickerOpens Opens { + get => _abpDatePickerOptionsImplementation.Opens; + set => _abpDatePickerOptionsImplementation.Opens = value; + } + + public AbpDatePickerDrops Drops { + get => _abpDatePickerOptionsImplementation.Drops; + set => _abpDatePickerOptionsImplementation.Drops = value; + } + + public string ButtonClasses { + get => _abpDatePickerOptionsImplementation.ButtonClasses; + set => _abpDatePickerOptionsImplementation.ButtonClasses = value; + } + + public string ApplyButtonClasses { + get => _abpDatePickerOptionsImplementation.ApplyButtonClasses; + set => _abpDatePickerOptionsImplementation.ApplyButtonClasses = value; + } + + public string CancelButtonClasses { + get => _abpDatePickerOptionsImplementation.CancelButtonClasses; + set => _abpDatePickerOptionsImplementation.CancelButtonClasses = value; + } + + public object Locale { + get => _abpDatePickerOptionsImplementation.Locale; + set => _abpDatePickerOptionsImplementation.Locale = value; + } + + public bool? AutoApply { + get => _abpDatePickerOptionsImplementation.AutoApply; + set => _abpDatePickerOptionsImplementation.AutoApply = value; + } + + public bool? LinkedCalendars { + get => _abpDatePickerOptionsImplementation.LinkedCalendars; + set => _abpDatePickerOptionsImplementation.LinkedCalendars = value; + } + + public bool? AutoUpdateInput { + get => _abpDatePickerOptionsImplementation.AutoUpdateInput; + set => _abpDatePickerOptionsImplementation.AutoUpdateInput = value; + } + + public string ParentEl { + get => _abpDatePickerOptionsImplementation.ParentEl; + set => _abpDatePickerOptionsImplementation.ParentEl = value; + } + + public string DateFormat { + get => _abpDatePickerOptionsImplementation.DateFormat; + set => _abpDatePickerOptionsImplementation.DateFormat = value; + } + + public bool OpenButton { + get => _abpDatePickerOptionsImplementation.OpenButton; + set => _abpDatePickerOptionsImplementation.OpenButton = value; + } + + public bool ClearButton { + get => _abpDatePickerOptionsImplementation.ClearButton; + set => _abpDatePickerOptionsImplementation.ClearButton = value; + } + + public bool? IsUtc { + get => _abpDatePickerOptionsImplementation.IsUtc; + set => _abpDatePickerOptionsImplementation.IsUtc = value; + } + + public bool? IsIso { + get => _abpDatePickerOptionsImplementation.IsIso; + set => _abpDatePickerOptionsImplementation.IsIso = value; + } + + public object Options { + get => _abpDatePickerOptionsImplementation.Options; + set => _abpDatePickerOptionsImplementation.Options = value; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs similarity index 78% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index d3a0026759..15e81e6c3d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -15,10 +15,9 @@ using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; -using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; using Volo.Abp.Json; -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelperService where TTagHelper : AbpDatePickerBaseTagHelper @@ -82,6 +81,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp AddDisabledAttribute(TagHelperOutput); AddAutoFocusAttribute(TagHelperOutput); AddFormControls(context, output, TagHelperOutput); + AddReadOnlyAttribute(TagHelperOutput); AddPlaceholderAttribute(TagHelperOutput); AddInfoTextId(TagHelperOutput); @@ -93,7 +93,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp ? await ProcessButtonAndGetContentAsync(context, output, "times", "clear") : ""; - var labelContent = TagHelper.SuppressLabel ? "" : await GetLabelAsHtmlAsync(context, output, TagHelperOutput); + var labelContent = await GetLabelAsHtmlAsync(context, output, TagHelperOutput); var infoContent = GetInfoAsHtml(context, output, TagHelperOutput); var validationContent = await GetValidationAsHtmlAsync(context, output); @@ -104,7 +104,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp TagHelperOutput.Render(Encoder) + openButtonContent + clearButtonContent + infoContent ); - var abpDatePickerTag = new TagHelperOutput(TagName, GetBaseTagAttributes(context, output), + var abpDatePickerTag = new TagHelperOutput(TagName, GetBaseTagAttributes(context, output, TagHelper), (_, _) => Task.FromResult(new DefaultTagHelperContent())); abpDatePickerTag.Content.AppendHtml(inputGroup.Render(Encoder)); abpDatePickerTag.Content.AppendHtml(validationContent); @@ -129,6 +129,15 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp output.Content.AppendHtml(innerHtml); } + + protected virtual void AddReadOnlyAttribute(TagHelperOutput inputTagHelperOutput) + { + if (inputTagHelperOutput.Attributes.ContainsName("readonly") == false && + (TagHelper.IsReadonly != false || GetAttribute() != null)) + { + inputTagHelperOutput.Attributes.Add("readonly", ""); + } + } protected virtual TagHelperAttributeList GetInputAttributes(TagHelperContext context, TagHelperOutput output) { @@ -205,75 +214,45 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp return string.Empty; } - protected TagHelperAttributeList GetBaseTagAttributes(TagHelperContext context, TagHelperOutput output) + protected TagHelperAttributeList ConvertDatePickerOptionsToAttributeList(IAbpDatePickerOptions options) { - var groupPrefix = "group-"; - - var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); - var attrList = new TagHelperAttributeList(); - - foreach (var tagHelperAttribute in tagHelperAttributes) - { - attrList.Add(tagHelperAttribute); - } - - if (attrList.ContainsName("type")) - { - attrList.Remove(attrList.First(a => a.Name == "type")); - } - - if (attrList.ContainsName("name")) - { - attrList.Remove(attrList.First(a => a.Name == "name")); - } - - if (attrList.ContainsName("id")) - { - attrList.Remove(attrList.First(a => a.Name == "id")); - } - - if (attrList.ContainsName("value")) - { - attrList.Remove(attrList.First(a => a.Name == "value")); - } - - if (TagHelper.Locale != null) + if (options.Locale != null) { - attrList.Add("data-locale", JsonSerializer.Serialize(TagHelper.Locale)); + attrList.Add("data-locale", JsonSerializer.Serialize(options.Locale)); } - if (TagHelper.MinDate != null) + if (options.MinDate != null) { - attrList.Add("data-min-date", TagHelper.MinDate); + attrList.Add("data-min-date", options.MinDate); } - if (TagHelper.MaxDate != null) + if (options.MaxDate != null) { - attrList.Add("data-max-date", TagHelper.MaxDate); + attrList.Add("data-max-date", options.MaxDate); } - if (TagHelper.MaxSpan != null) + if (options.MaxSpan != null) { - attrList.Add("data-max-span", JsonSerializer.Serialize(TagHelper.MaxSpan)); + attrList.Add("data-max-span", JsonSerializer.Serialize(options.MaxSpan)); } - if (TagHelper.ShowDropdowns == false) + if (options.ShowDropdowns == false) { - attrList.Add("data-show-dropdowns", TagHelper.ShowDropdowns.ToString().ToLowerInvariant()); + attrList.Add("data-show-dropdowns", options.ShowDropdowns.ToString().ToLowerInvariant()); } - if (TagHelper.MinYear != null) + if (options.MinYear != null) { - attrList.Add("data-min-year", TagHelper.MinYear); + attrList.Add("data-min-year", options.MinYear); } - if (TagHelper.MaxYear != null) + if (options.MaxYear != null) { - attrList.Add("data-max-year", TagHelper.MaxYear); + attrList.Add("data-max-year", options.MaxYear); } - switch (TagHelper.WeekNumbers) + switch (options.WeekNumbers) { case AbpDatePickerWeekNumbers.Normal: attrList.Add("data-show-week-numbers", "true"); @@ -283,106 +262,161 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp break; } - if (TagHelper.TimePicker != null) + if (options.TimePicker != null) { - attrList.Add("data-time-picker", TagHelper.TimePicker.ToString().ToLowerInvariant()); + attrList.Add("data-time-picker", options.TimePicker.ToString().ToLowerInvariant()); } - if (TagHelper.TimePickerIncrement != null) + if (options.TimePickerIncrement != null) { - attrList.Add("data-time-picker-increment", TagHelper.TimePickerIncrement); + attrList.Add("data-time-picker-increment", options.TimePickerIncrement); } - if (TagHelper.TimePicker24Hour != null) + if (options.TimePicker24Hour != null) { - attrList.Add("data-time-picker24-hour", TagHelper.TimePicker24Hour.ToString().ToLowerInvariant()); + attrList.Add("data-time-picker24-hour", options.TimePicker24Hour.ToString().ToLowerInvariant()); } - if (TagHelper.TimePickerSeconds != null) + if (options.TimePickerSeconds != null) { - attrList.Add("data-time-picker-seconds", TagHelper.TimePickerSeconds.ToString().ToLowerInvariant()); + attrList.Add("data-time-picker-seconds", options.TimePickerSeconds.ToString().ToLowerInvariant()); } - if (TagHelper.Opens != AbpDatePickerOpens.Center) + if (options.Opens != AbpDatePickerOpens.Center) { - attrList.Add("data-opens", TagHelper.Opens.ToString().ToLowerInvariant()); + attrList.Add("data-opens", options.Opens.ToString().ToLowerInvariant()); } - if (TagHelper.Drops != AbpDatePickerDrops.Down) + if (options.Drops != AbpDatePickerDrops.Down) { - attrList.Add("data-drops", TagHelper.Drops.ToString().ToLowerInvariant()); + attrList.Add("data-drops", options.Drops.ToString().ToLowerInvariant()); } - if (!TagHelper.ButtonClasses.IsNullOrEmpty()) + if (!options.ButtonClasses.IsNullOrEmpty()) { - attrList.Add("data-button-classes", TagHelper.ButtonClasses); + attrList.Add("data-button-classes", options.ButtonClasses); } - if (!TagHelper.ApplyButtonClasses.IsNullOrEmpty()) + if (!options.ApplyButtonClasses.IsNullOrEmpty()) { - attrList.Add("data-apply-button-classes", TagHelper.ApplyButtonClasses); + attrList.Add("data-apply-button-classes", options.ApplyButtonClasses); } - if (!TagHelper.CancelButtonClasses.IsNullOrEmpty()) + if (!options.CancelButtonClasses.IsNullOrEmpty()) { - attrList.Add("data-cancel-button-classes", TagHelper.CancelButtonClasses); + attrList.Add("data-cancel-button-classes", options.CancelButtonClasses); } - if (!TagHelper.AutoApply) + if (options.AutoApply != null) { - attrList.Add("data-auto-apply", TagHelper.AutoApply.ToString().ToLowerInvariant()); + attrList.Add("data-auto-apply", options.AutoApply.ToString().ToLowerInvariant()); } - if (TagHelper.LinkedCalendars != null) + if (options.LinkedCalendars != null) { - attrList.Add("data-linked-calendars", TagHelper.LinkedCalendars.ToString().ToLowerInvariant()); + attrList.Add("data-linked-calendars", options.LinkedCalendars.ToString().ToLowerInvariant()); } - if (TagHelper.AutoUpdateInput) + if (options.AutoUpdateInput != null) { - attrList.Add("data-auto-update-input", TagHelper.AutoUpdateInput.ToString().ToLowerInvariant()); + attrList.Add("data-auto-update-input", options.AutoUpdateInput.ToString().ToLowerInvariant()); } - if (!TagHelper.ParentEl.IsNullOrEmpty()) + if (!options.ParentEl.IsNullOrEmpty()) { - attrList.Add("data-parent-el", TagHelper.ParentEl); + attrList.Add("data-parent-el", options.ParentEl); } - if (!TagHelper.DateFormat.IsNullOrEmpty()) + if (!options.DateFormat.IsNullOrEmpty()) { - attrList.Add("data-date-format", TagHelper.DateFormat); + attrList.Add("data-date-format", options.DateFormat); } - if(TagHelper.Ranges != null && TagHelper.Ranges.Any()) + if(options.Ranges != null && options.Ranges.Any()) { - var ranges = TagHelper.Ranges.ToDictionary(r => r.Label, r => r.Dates); + var ranges = options.Ranges.ToDictionary(r => r.Label, r => r.Dates); attrList.Add("data-ranges", JsonSerializer.Serialize(ranges)); } - if(TagHelper.AlwaysShowCalendars) + if(options.AlwaysShowCalendars != null) { - attrList.Add("data-always-show-calendars", TagHelper.AlwaysShowCalendars.ToString().ToLowerInvariant()); + attrList.Add("data-always-show-calendars", options.AlwaysShowCalendars.ToString().ToLowerInvariant()); } - if(TagHelper.ShowCustomRangeLabel == false) + if(options.ShowCustomRangeLabel == false) { - attrList.Add("data-show-custom-range-label", TagHelper.ShowCustomRangeLabel.ToString().ToLowerInvariant()); + attrList.Add("data-show-custom-range-label", options.ShowCustomRangeLabel.ToString().ToLowerInvariant()); } - if(TagHelper.Options != null) + if(options.Options != null) { - attrList.Add("data-options", JsonSerializer.Serialize(TagHelper.Options)); + attrList.Add("data-options", JsonSerializer.Serialize(options.Options)); } - if (TagHelper.IsUtc) + if (options.IsUtc != null) { attrList.Add("data-is-utc", "true"); } - if (TagHelper.IsIso) + if (options.IsIso != null) + { + attrList.Add("data-is-iso", options.IsIso.ToString().ToLowerInvariant()); + } + + if (!options.PickerId.IsNullOrWhiteSpace()) { - attrList.Add("data-is-iso", TagHelper.IsIso.ToString().ToLowerInvariant()); + attrList.Add("id", options.PickerId); + } + + return attrList; + } + + protected TagHelperAttributeList GetBaseTagAttributes(TagHelperContext context, TagHelperOutput output, IAbpDatePickerOptions options) + { + var groupPrefix = "group-"; + + var tagHelperAttributes = output.Attributes.Where(a => !a.Name.StartsWith(groupPrefix)).ToList(); + + var attrList = new TagHelperAttributeList(); + + foreach (var tagHelperAttribute in tagHelperAttributes) + { + attrList.Add(tagHelperAttribute); + } + + if (attrList.ContainsName("type")) + { + attrList.Remove(attrList.First(a => a.Name == "type")); + } + + if (attrList.ContainsName("name")) + { + attrList.Remove(attrList.First(a => a.Name == "name")); + } + + if (attrList.ContainsName("id")) + { + attrList.Remove(attrList.First(a => a.Name == "id")); + } + + if (attrList.ContainsName("value")) + { + attrList.Remove(attrList.First(a => a.Name == "value")); + } + + foreach (var attr in ConvertDatePickerOptionsToAttributeList(options)) + { + attrList.Add(attr); + } + + var optionsAttribute = GetAttribute(); + if(optionsAttribute != null) + { + foreach (var attr in ConvertDatePickerOptionsToAttributeList(optionsAttribute)) + { + attrList.Add(attr); + } } AddBaseTagAttributes(attrList); @@ -440,6 +474,10 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp protected virtual async Task GetLabelAsHtmlAsync(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag) { + if (IsOutputHidden(inputTag) || TagHelper.SuppressLabel) + { + return string.Empty; + } if (string.IsNullOrEmpty(TagHelper.Label)) { return await GetLabelAsHtmlUsingTagHelperAsync(context, output) + GetRequiredSymbol(context, output); @@ -489,9 +527,14 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp protected virtual async Task GetLabelAsHtmlUsingTagHelperAsync(TagHelperContext context, TagHelperOutput output) { + var modelExpression = GetModelExpression(); + if (modelExpression == null) + { + return string.Empty; + } var labelTagHelper = new LabelTagHelper(Generator) { ViewContext = TagHelper.ViewContext, - For = GetModelExpression() + For = modelExpression }; var attributeList = new TagHelperAttributeList(); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs new file mode 100644 index 0000000000..7e26e27c66 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerDrops +{ + Down, + Up, + Auto +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs new file mode 100644 index 0000000000..a69ead079d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerOpens +{ + Left, + Right, + Center +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs new file mode 100644 index 0000000000..9a3e45f35e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs @@ -0,0 +1,39 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public class AbpDatePickerOptions : IAbpDatePickerOptions +{ + public string PickerId { get; set; } + public DateTime? MinDate { get; set; } + public DateTime? MaxDate { get; set; } + public object MaxSpan { get; set; } + public bool? ShowDropdowns { get; set; } + public int? MinYear { get; set; } + public int? MaxYear { get; set; } + public AbpDatePickerWeekNumbers WeekNumbers { get; set; } = AbpDatePickerWeekNumbers.None; + public bool? TimePicker { get; set; } + public int? TimePickerIncrement { get; set; } + public bool? TimePicker24Hour { get; set; } + public bool? TimePickerSeconds { get; set; } + public List Ranges { get; set; } + public bool? ShowCustomRangeLabel { get; set; } + public bool? AlwaysShowCalendars { get; set; } + public AbpDatePickerOpens Opens { get; set; } = AbpDatePickerOpens.Center; + public AbpDatePickerDrops Drops { get; set; } = AbpDatePickerDrops.Down; + public string ButtonClasses { get; set; } + public string ApplyButtonClasses { get; set; } + public string CancelButtonClasses { get; set; } + public object Locale { get; set; } + public bool? AutoApply { get; set; } + public bool? LinkedCalendars { get; set; } + public bool? AutoUpdateInput { get; set; } + public string ParentEl { get; set; } + public string DateFormat { get; set; } + public bool OpenButton { get; set; } = true; + public bool ClearButton { get; set; } = true; + public bool? IsUtc { get; set; } + public bool? IsIso { get; set; } + public object Options { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs similarity index 92% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs index 8643668283..727110c56c 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerRange.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs @@ -1,7 +1,7 @@ using System; using System.Collections.Generic; -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; public class AbpDatePickerRange { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs new file mode 100644 index 0000000000..8426b0071b --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelper.cs @@ -0,0 +1,16 @@ +using JetBrains.Annotations; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[HtmlTargetElement("abp-date-picker", TagStructure = TagStructure.NormalOrSelfClosing)] +public class AbpDatePickerTagHelper : AbpDatePickerBaseTagHelper +{ + [CanBeNull] + public ModelExpression AspFor { get; set; } + + public AbpDatePickerTagHelper(AbpDatePickerTagHelperService service) : base(service) + { + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs similarity index 87% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs index a368037451..8007a13a17 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDatePickerTag.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs @@ -10,20 +10,7 @@ using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; using Volo.Abp.Json; -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; - -[HtmlTargetElement("abp-date-picker", TagStructure = TagStructure.NormalOrSelfClosing)] -public class AbpDatePickerTagHelper : AbpDatePickerBaseTagHelper -{ - [CanBeNull] - public ModelExpression AspFor { get; set; } - - public AbpDatePickerTagHelper(AbpDatePickerTagHelperService service) : base(service) - { - } -} - - +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; public class AbpDatePickerTagHelperService : AbpDatePickerBaseTagHelperService { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs new file mode 100644 index 0000000000..95f5c911e7 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerWeekNumbers.cs @@ -0,0 +1,8 @@ +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerWeekNumbers +{ + None, + Normal, + Iso +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs new file mode 100644 index 0000000000..97221a0d7d --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelper.cs @@ -0,0 +1,21 @@ +using JetBrains.Annotations; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[HtmlTargetElement("abp-date-range-picker", TagStructure = TagStructure.NormalOrSelfClosing)] +public class AbpDateRangePickerTagHelper : AbpDatePickerBaseTagHelper +{ + // Start date + [CanBeNull] + public ModelExpression AspForStart { get; set; } + + // End date + [CanBeNull] + public ModelExpression AspForEnd { get; set; } + + public AbpDateRangePickerTagHelper(AbpDateRangePickerTagHelperService tagHelperService) : base(tagHelperService) + { + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs similarity index 88% rename from framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs rename to framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs index 9f88e2f5a3..a869147bfd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/DatePicker/AbpDateRangePicker.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs @@ -1,6 +1,5 @@ using System; using System.Linq; -using System.Text; using System.Text.Encodings.Web; using System.Threading.Tasks; using JetBrains.Annotations; @@ -12,23 +11,7 @@ using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; using Volo.Abp.Json; -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.DatePicker; - -[HtmlTargetElement("abp-date-range-picker", TagStructure = TagStructure.NormalOrSelfClosing)] -public class AbpDateRangePickerTagHelper : AbpDatePickerBaseTagHelper -{ - // Start date - [CanBeNull] - public ModelExpression AspForStart { get; set; } - - // End date - [CanBeNull] - public ModelExpression AspForEnd { get; set; } - - public AbpDateRangePickerTagHelper(AbpDateRangePickerTagHelperService tagHelperService) : base(tagHelperService) - { - } -} +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperService { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs new file mode 100644 index 0000000000..840e21241e --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerAttribute.cs @@ -0,0 +1,8 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[AttributeUsage(AttributeTargets.Property)] +public class DatePickerAttribute : Attribute +{ +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs new file mode 100644 index 0000000000..612ab94216 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -0,0 +1,169 @@ +using System; +using System.Collections.Generic; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public class DatePickerOptionsAttribute : Attribute, IAbpDatePickerOptions +{ + private IAbpDatePickerOptions _abpDatePickerOptionsImplementation; + + public DatePickerOptionsAttribute() + { + _abpDatePickerOptionsImplementation = new AbpDatePickerOptions(); + } + + public string PickerId { + get => _abpDatePickerOptionsImplementation.PickerId; + set => _abpDatePickerOptionsImplementation.PickerId = value; + } + + public DateTime? MinDate { + get => _abpDatePickerOptionsImplementation.MinDate; + set => _abpDatePickerOptionsImplementation.MinDate = value; + } + + public DateTime? MaxDate { + get => _abpDatePickerOptionsImplementation.MaxDate; + set => _abpDatePickerOptionsImplementation.MaxDate = value; + } + + public object MaxSpan { + get => _abpDatePickerOptionsImplementation.MaxSpan; + set => _abpDatePickerOptionsImplementation.MaxSpan = value; + } + + public bool? ShowDropdowns { + get => _abpDatePickerOptionsImplementation.ShowDropdowns; + set => _abpDatePickerOptionsImplementation.ShowDropdowns = value; + } + + public int? MinYear { + get => _abpDatePickerOptionsImplementation.MinYear; + set => _abpDatePickerOptionsImplementation.MinYear = value; + } + + public int? MaxYear { + get => _abpDatePickerOptionsImplementation.MaxYear; + set => _abpDatePickerOptionsImplementation.MaxYear = value; + } + + public AbpDatePickerWeekNumbers WeekNumbers { + get => _abpDatePickerOptionsImplementation.WeekNumbers; + set => _abpDatePickerOptionsImplementation.WeekNumbers = value; + } + + public bool? TimePicker { + get => _abpDatePickerOptionsImplementation.TimePicker; + set => _abpDatePickerOptionsImplementation.TimePicker = value; + } + + public int? TimePickerIncrement { + get => _abpDatePickerOptionsImplementation.TimePickerIncrement; + set => _abpDatePickerOptionsImplementation.TimePickerIncrement = value; + } + + public bool? TimePicker24Hour { + get => _abpDatePickerOptionsImplementation.TimePicker24Hour; + set => _abpDatePickerOptionsImplementation.TimePicker24Hour = value; + } + + public bool? TimePickerSeconds { + get => _abpDatePickerOptionsImplementation.TimePickerSeconds; + set => _abpDatePickerOptionsImplementation.TimePickerSeconds = value; + } + + public List Ranges { + get => _abpDatePickerOptionsImplementation.Ranges; + set => _abpDatePickerOptionsImplementation.Ranges = value; + } + + public bool? ShowCustomRangeLabel { + get => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel; + set => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel = value; + } + + public bool? AlwaysShowCalendars { + get => _abpDatePickerOptionsImplementation.AlwaysShowCalendars; + set => _abpDatePickerOptionsImplementation.AlwaysShowCalendars = value; + } + + public AbpDatePickerOpens Opens { + get => _abpDatePickerOptionsImplementation.Opens; + set => _abpDatePickerOptionsImplementation.Opens = value; + } + + public AbpDatePickerDrops Drops { + get => _abpDatePickerOptionsImplementation.Drops; + set => _abpDatePickerOptionsImplementation.Drops = value; + } + + public string ButtonClasses { + get => _abpDatePickerOptionsImplementation.ButtonClasses; + set => _abpDatePickerOptionsImplementation.ButtonClasses = value; + } + + public string ApplyButtonClasses { + get => _abpDatePickerOptionsImplementation.ApplyButtonClasses; + set => _abpDatePickerOptionsImplementation.ApplyButtonClasses = value; + } + + public string CancelButtonClasses { + get => _abpDatePickerOptionsImplementation.CancelButtonClasses; + set => _abpDatePickerOptionsImplementation.CancelButtonClasses = value; + } + + public object Locale { + get => _abpDatePickerOptionsImplementation.Locale; + set => _abpDatePickerOptionsImplementation.Locale = value; + } + + public bool? AutoApply { + get => _abpDatePickerOptionsImplementation.AutoApply; + set => _abpDatePickerOptionsImplementation.AutoApply = value; + } + + public bool? LinkedCalendars { + get => _abpDatePickerOptionsImplementation.LinkedCalendars; + set => _abpDatePickerOptionsImplementation.LinkedCalendars = value; + } + + public bool? AutoUpdateInput { + get => _abpDatePickerOptionsImplementation.AutoUpdateInput; + set => _abpDatePickerOptionsImplementation.AutoUpdateInput = value; + } + + public string ParentEl { + get => _abpDatePickerOptionsImplementation.ParentEl; + set => _abpDatePickerOptionsImplementation.ParentEl = value; + } + + public string DateFormat { + get => _abpDatePickerOptionsImplementation.DateFormat; + set => _abpDatePickerOptionsImplementation.DateFormat = value; + } + + public bool OpenButton { + get => _abpDatePickerOptionsImplementation.OpenButton; + set => _abpDatePickerOptionsImplementation.OpenButton = value; + } + + public bool ClearButton { + get => _abpDatePickerOptionsImplementation.ClearButton; + set => _abpDatePickerOptionsImplementation.ClearButton = value; + } + + public bool? IsUtc { + get => _abpDatePickerOptionsImplementation.IsUtc; + set => _abpDatePickerOptionsImplementation.IsUtc = value; + } + + public bool? IsIso { + get => _abpDatePickerOptionsImplementation.IsIso; + set => _abpDatePickerOptionsImplementation.IsIso = value; + } + + public object Options { + get => _abpDatePickerOptionsImplementation.Options; + set => _abpDatePickerOptionsImplementation.Options = value; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs new file mode 100644 index 0000000000..7892df6918 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs @@ -0,0 +1,16 @@ +using System; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +[AttributeUsage(AttributeTargets.Property)] +public class DateRangePickerAttribute : Attribute +{ + public string PickerId { get; set; } + public bool IsStart { get; set; } + + public DateRangePickerAttribute(string pickerId, bool isStart = false) + { + PickerId = pickerId; + IsStart = isStart; + } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs new file mode 100644 index 0000000000..f6813417e6 --- /dev/null +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs @@ -0,0 +1,100 @@ +using System; +using System.Collections.Generic; +using JetBrains.Annotations; + +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public interface IAbpDatePickerOptions +{ + public string PickerId { get; set; } + // Min and Max date + DateTime? MinDate { get; set; } + + DateTime? MaxDate { get; set; } + + // Max span between start and end date + object? MaxSpan { get; set; } + + // Show dropdowns + bool? ShowDropdowns { get; set; } + + // Min and Max year + int? MinYear { get; set; } + + int? MaxYear { get; set; } + + // Show week numbers + AbpDatePickerWeekNumbers WeekNumbers { get; set; } + + // Time picker + bool? TimePicker { get; set; } + + // Time picker increment + int? TimePickerIncrement { get; set; } + + // Time picker 24 hour + bool? TimePicker24Hour { get; set; } + + // Time picker seconds + bool? TimePickerSeconds { get; set; } + + // Ranges object + List Ranges { get; set; } + + // Show custom range label + bool? ShowCustomRangeLabel { get; set; } + + // Always show calendar + bool? AlwaysShowCalendars { get; set; } + + // Opens date picker on left or right or center of the input + AbpDatePickerOpens Opens { get; set; } + + // Drops down or up or auto + AbpDatePickerDrops Drops { get; set; } + + // Button classes + [CanBeNull] + string ButtonClasses { get; set; } + + // Apply class to all buttons + [CanBeNull] + string ApplyButtonClasses { get; set; } + + // Cancel class to all buttons + [CanBeNull] + string CancelButtonClasses { get; set; } + + // Locale + [CanBeNull] + object Locale { get; set; } + + // Auto apply + bool? AutoApply { get; set; } + + // Linked calendars + bool? LinkedCalendars { get; set; } + + // Auto update input + bool? AutoUpdateInput { get; set; } + + // Parent element + [CanBeNull] + string ParentEl { get; set; } + + // DatePickerType Type { get; set; } = DatePickerType.Date; + + [CanBeNull] + string DateFormat { get; set; } + + bool OpenButton { get; set; } + + bool ClearButton { get; set; } + + bool? IsUtc { get; set; } + + bool? IsIso { get; set; } + + [CanBeNull] + object Options { get; set; } +} \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index acbb0908e9..e47bd840a4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -288,9 +288,6 @@ } $container.data('options', options); - if($container.data('options', options)){ - debugger; - } abp.dom.initializers.initializeDateRangePickers($container); return $container; } @@ -310,23 +307,29 @@ var $clearButton = $(this).find('button[data-type="clear"]') var singleDatePicker = $this.is('abp-date-picker') var options = {}; + options.singleDatePicker = singleDatePicker; var defaultOptions = { showDropdowns: true, opens: "center", drops: "down", autoApply: true, - autoUpdateInput: false + autoUpdateInput: false, + minYear: parseInt(moment().subtract(100, 'year').locale('en').format('YYYY')), + maxYear: parseInt(moment().add(100, 'year').locale('en').format('YYYY')), + locale: { + direction: abp.localization.currentCulture.isRightToLeft ? 'rtl' : 'ltr', + }, }; $.extend(options, defaultOptions); $.extend(options, $this.data()); - if($this.data("options")){ - debugger; - $.extend(options, $this.data("options")); - } $.extend(options, $this.data("options")); + if(options.timePicker && options.timePicker24Hour === undefined){ + options.timePicker24Hour = moment.localeData().longDateFormat('LT').indexOf('A') < 1; + } + var isUtc = options.isUtc; var isIso = options.isIso; var timePicker = options.timePicker; @@ -334,6 +337,7 @@ var timePickerSeconds = options.timePickerSeconds; var dateFormat = options.dateFormat; var separator = options.separator; + var defaultDateFormat = "YYYY-MM-DD"; const getMoment = function (date) { if(!date){ return isUtc ? moment.utc() : moment(); @@ -404,27 +408,30 @@ $dateRangePicker.toggle(); }); - - if(!dateFormat) { + const extendDateFormat = function (format) { if(timePicker){ if(timePicker24Hour){ if(timePickerSeconds){ - dateFormat = moment.localeData().longDateFormat('L') + " HH:mm:ss"; + format += " HH:mm:ss"; }else{ - dateFormat = moment.localeData().longDateFormat('L') + " HH:mm"; + format += " HH:mm"; } }else { if (timePickerSeconds) { - dateFormat = moment.localeData().longDateFormat('L') + ' ' + " hh:mm:ss A" + format += ' ' + " hh:mm:ss A" } else { - dateFormat = moment.localeData().longDateFormat('L') + " hh:mm A"; + format += " hh:mm A"; } } - }else{ - dateFormat = moment.localeData().longDateFormat('L'); } + return format; } + defaultDateFormat = extendDateFormat(defaultDateFormat); + + if(!dateFormat) { + dateFormat = extendDateFormat(moment.localeData().longDateFormat('L')) + } if(!separator) { separator = $dateRangePicker.locale.separator; @@ -524,11 +531,10 @@ function formatDate(date){ if(date){ - debugger; if(isIso){ - return date.format(); + return date.locale('en').format(); } - return date.format(dateFormat) + return date.locale('en').format(defaultDateFormat) } return null; } @@ -560,6 +566,8 @@ $input[0].getFormattedStartDate = getFormattedStartDate; $input[0].getFormattedEndDate = getFormattedEndDate; } + + $input.trigger('change'); }); } From a8878a1e01eb078137c3a91f486dea9b3595d69f Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Feb 2023 20:39:55 +0300 Subject: [PATCH 06/28] Update AbpDynamicformTagHelperService.cs --- .../Form/AbpDynamicformTagHelperService.cs | 74 +++++++++++++++++++ 1 file changed, 74 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs index 38f55ca04e..17383b46d6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs @@ -14,6 +14,7 @@ using Microsoft.Extensions.Localization; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.Microsoft.AspNetCore.Razor.TagHelpers; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Button; using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Extensions; +using Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form; @@ -144,6 +145,10 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService(); + abpDateInputTagHelper.AspFor = model; + abpDateInputTagHelper.ViewContext = TagHelper.ViewContext; + abpDateInputTagHelper.DisplayRequiredSymbol = TagHelper.RequiredSymbols ?? true; + return abpDateInputTagHelper; + } + + private AbpTagHelper GetAbpDateRangeInputTagHelper(TagHelperContext context, TagHelperOutput output, + ModelExpression model) + { + var modelAttribute = model.ModelExplorer.GetAttribute(); + + var pickerId = modelAttribute.PickerId; + var otherModel = TagHelper.Model.ModelExplorer.Properties.SingleOrDefault(x => + x != model.ModelExplorer && x.GetAttribute()?.PickerId == pickerId); + var otherModelAttribute = otherModel?.GetAttribute(); + + var abpDateRangeInputTagHelper = _serviceProvider.GetRequiredService(); + abpDateRangeInputTagHelper.PickerId = pickerId; + abpDateRangeInputTagHelper.ViewContext = TagHelper.ViewContext; + if (modelAttribute.IsStart) + { + abpDateRangeInputTagHelper.AspForStart = model; + } + + if (otherModelAttribute?.IsStart == false) + { + abpDateRangeInputTagHelper.AspForEnd = ModelExplorerToModelExpressionConverter(otherModel); + } + + return abpDateRangeInputTagHelper; + } + + + private bool IsDateRangeGroup(ModelExplorer modelModelExplorer) + { + return modelModelExplorer.GetAttribute() != null; + } + protected virtual void RemoveFormGroupItemsNotInModel(TagHelperContext context, TagHelperOutput output, List items) { var models = GetModels(context, output); @@ -293,6 +353,20 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService() != null || model.ModelExplorer.GetAttribute() != null) + { + return true; + } + + if(model.Metadata.ModelType == typeof(DateTime) || model.Metadata.ModelType == typeof(DateTime?) || model.Metadata.ModelType == typeof(DateTimeOffset) || model.Metadata.ModelType == typeof(DateTimeOffset?)) + { + return true; + } + return false; + } protected virtual bool IsEnum(ModelExplorer explorer) { From 7d91847b6e7a96b5ec6ff208a66ab87fd1c06d8e Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Feb 2023 20:40:00 +0300 Subject: [PATCH 07/28] Update Form-elements.md --- .../AspNetCore/Tag-Helpers/Form-elements.md | 96 +++++++++++++++++++ 1 file changed, 96 insertions(+) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 8f664a80a5..99fadbc84c 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -261,3 +261,99 @@ You can set some of the attributes on your c# property, or directly on html tag. - `asp-items`: Sets the select data. This Should be a list of SelectListItem. - `Inline`: If true, radio buttons will be in single line, next to each other. If false, they will be under each other. + +## abp-date-picker & abp-date-range-picker + +`abp-date-picker` and `abp-date-range-picker` tags creates a Bootstrap form date picker for a given c# property. `abp-date-picker` is for single date selection, `abp-date-range-picker` is for date range selection. It uses [datepicker](https://www.daterangepicker.com/) jQuery plugin. + +Usage: + +````xml + + +```` + +Model: + +````csharp + public class FormElementsModel : PageModel + { + public SampleModel MyModel { get; set; } + + public void OnGet() + { + MyModel = new SampleModel(); + } + + public class SampleModel + { + public DateTime MyDate { get; set; } + + public DateTime MyDateRangeStart { get; set; } + + public DateTime MyDateRangeEnd { get; set; } + } + } +```` + +### Attributes + +You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. + +#### Property Attributes + +* `[Placeholder()]`: Sets placeholder for input. You can use a localization key directly. +* `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly. +* `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `[DisabledInput]` : Input is disabled. +* `[ReadOnlyInput]`: Input is read-only. +- `[DatePickerOptions()]`: Sets the options of datepicker. You can use a localization key directly. See [datepicker options](https://www.daterangepicker.com/#options) for more information.) + +##### abp-date-picker +`[DatePicker]` : Date picker is enabled. + +##### abp-date-range-picker +`[DateRangePicker()]` : Sets the picker id for date range picker. This is used to link start and end date pickers. And sets this property is start date or end date. + +#### Tag Attributes + +* `info`: Sets a small info text for input. You can use a localization key directly. +* `auto-focus`: If true, browser auto focuses on the element. +* `size`: Sets size of form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `disabled`: Input is disabled. +* `readonly`: Input is read-only. +* `label`: Sets the label for input. +* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. +* `open-button`: If true, a button will be added to open datepicker. Default `True`. +* `clear-button`: If true, a button will be added to clear datepicker. Default `True`. +* `is-utc`: If true, datepicker will use UTC date. Default `False`. +* `is-iso`: If true, datepicker will use ISO date. Default `False`. +* `date-format`: Sets the date format. Default your culture's date format. +* `date-separator`: Sets the range date separator. Default `-`. +* Other attributes will be added to the input element and [datepicker options](https://www.daterangepicker.com/#options). + +##### abp-date-picker + +* `asp-date`: Sets the date value. This should be a `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` or `string` value. + +##### abp-date-range-picker + +* `asp-for-start`: Sets the start date value. This should be a `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` or `string` value. +* `asp-for-end`: Sets the end date value. This should be a `DateTime`, `DateTime?`, `DateTimeOffset`, `DateTimeOffset?` or `string` value. + +### Label & Localization + +You can set label of your input in different ways: + +- You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value"`. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core. +- You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys, if `label` or `[DisplayName]` attributes are not set. + From 0ede3d7c18f18db1c2f314da9c67c60263b2e210 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Feb 2023 22:04:54 +0300 Subject: [PATCH 08/28] Update Form-elements.md --- .../TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs | 1 + 1 file changed, 1 insertion(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs index 612ab94216..b911a7021e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -3,6 +3,7 @@ using System.Collections.Generic; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; +[AttributeUsage(AttributeTargets.Property)] public class DatePickerOptionsAttribute : Attribute, IAbpDatePickerOptions { private IAbpDatePickerOptions _abpDatePickerOptionsImplementation; From 1516367b48544daf66c4a036c8c7fad0bdce0c45 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Feb 2023 22:04:59 +0300 Subject: [PATCH 09/28] Update Form-elements.md --- docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 99fadbc84c..df8c5008ac 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -336,7 +336,7 @@ You can set some of the attributes on your c# property, or directly on html tag. * `clear-button`: If true, a button will be added to clear datepicker. Default `True`. * `is-utc`: If true, datepicker will use UTC date. Default `False`. * `is-iso`: If true, datepicker will use ISO date. Default `False`. -* `date-format`: Sets the date format. Default your culture's date format. +* `date-format`: Sets the date format. Default your culture's date format. (JS format) * `date-separator`: Sets the range date separator. Default `-`. * Other attributes will be added to the input element and [datepicker options](https://www.daterangepicker.com/#options). From 4db3e7e671361e41dbf6e10d00a15cba8fbd5e3a Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Feb 2023 22:52:50 +0300 Subject: [PATCH 10/28] Refactoring --- .../Form/DatePicker/AbpDatePickerBaseTagHelperService.cs | 2 +- .../bootstrap/dom-event-handlers.js | 6 +++--- 2 files changed, 4 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index 15e81e6c3d..6359e15cbd 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -356,7 +356,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp if (options.IsUtc != null) { - attrList.Add("data-is-utc", "true"); + attrList.Add("data-is-utc", options.IsUtc.ToString().ToLowerInvariant()); } if (options.IsIso != null) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index e47bd840a4..35b19292cc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -359,11 +359,11 @@ options.locale.separator = separator; } - var startDate = options.startDate ? getMoment(options.startDate) : null; + var startDate = options.startDate ? moment(options.startDate) : null; if(singleDatePicker && !startDate){ - startDate = options.date ? getMoment(options.date) : null; + startDate = options.date ? moment(options.date) : null; } - var endDate = options.endDate ? getMoment(options.endDate) : null; + var endDate = options.endDate ? moment(options.endDate) : null; if (startDate) { options.startDate = startDate; From 7e58ee46cf978064f3bde965f339adc6262d655e Mon Sep 17 00:00:00 2001 From: Salih Date: Sat, 25 Feb 2023 14:53:46 +0300 Subject: [PATCH 11/28] Refactoring --- .../Form/DatePicker/AbpDatePickerBaseTagHelper.cs | 5 +++++ .../AbpDatePickerBaseTagHelperService.cs | 14 ++++++++++++-- .../Form/DatePicker/AbpDatePickerOptions.cs | 1 + .../Form/DatePicker/DatePickerOptionsAttribute.cs | 5 +++++ .../Form/DatePicker/IAbpDatePickerOptions.cs | 4 ++-- 5 files changed, 25 insertions(+), 4 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs index 75c3291901..a85a41f7e8 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs @@ -191,6 +191,11 @@ public abstract class set => _abpDatePickerOptionsImplementation.ClearButton = value; } + public bool SingleOpenAndClearButton { + get => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton; + set => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton = value; + } + public bool? IsUtc { get => _abpDatePickerOptionsImplementation.IsUtc; set => _abpDatePickerOptionsImplementation.IsUtc = value; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index 6359e15cbd..67b20c3c5e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -90,7 +90,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp ? await ProcessButtonAndGetContentAsync(context, output, "calendar", "open") : ""; var clearButtonContent = TagHelper.ClearButton - ? await ProcessButtonAndGetContentAsync(context, output, "times", "clear") + ? await ProcessButtonAndGetContentAsync(context, output, "times", "clear", visible:!TagHelper.SingleOpenAndClearButton) : ""; var labelContent = await GetLabelAsHtmlAsync(context, output, TagHelperOutput); @@ -369,6 +369,11 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp attrList.Add("id", options.PickerId); } + if(!options.SingleOpenAndClearButton) + { + attrList.Add("data-single-open-and-clear-button", options.SingleOpenAndClearButton.ToString().ToLowerInvariant()); + } + return attrList; } @@ -564,13 +569,18 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp } protected virtual async Task ProcessButtonAndGetContentAsync(TagHelperContext context, - TagHelperOutput output, string icon, string type) + TagHelperOutput output, string icon, string type, bool visible = true) { var abpButtonTagHelper = ServiceProvider.GetRequiredService(); var attributes = new TagHelperAttributeList { new("type", "button"), new("tabindex", "-1"), new("data-type", type) }; abpButtonTagHelper.ButtonType = AbpButtonType.Outline_Secondary; abpButtonTagHelper.Icon = icon; + + if (!visible) + { + attributes.AddClass("d-none"); + } return await abpButtonTagHelper.RenderAsync(attributes, context, Encoder, "button", TagMode.StartTagAndEndTag); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs index 9a3e45f35e..4dfdd3b86a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs @@ -33,6 +33,7 @@ public class AbpDatePickerOptions : IAbpDatePickerOptions public string DateFormat { get; set; } public bool OpenButton { get; set; } = true; public bool ClearButton { get; set; } = true; + public bool SingleOpenAndClearButton { get; set; } = true; public bool? IsUtc { get; set; } public bool? IsIso { get; set; } public object Options { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs index b911a7021e..3b2d605be4 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -153,6 +153,11 @@ public class DatePickerOptionsAttribute : Attribute, IAbpDatePickerOptions set => _abpDatePickerOptionsImplementation.ClearButton = value; } + public bool SingleOpenAndClearButton { + get => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton; + set => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton = value; + } + public bool? IsUtc { get => _abpDatePickerOptionsImplementation.IsUtc; set => _abpDatePickerOptionsImplementation.IsUtc = value; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs index f6813417e6..993af0c41f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs @@ -82,14 +82,14 @@ public interface IAbpDatePickerOptions [CanBeNull] string ParentEl { get; set; } - // DatePickerType Type { get; set; } = DatePickerType.Date; - [CanBeNull] string DateFormat { get; set; } bool OpenButton { get; set; } bool ClearButton { get; set; } + + bool SingleOpenAndClearButton { get; set; } bool? IsUtc { get; set; } From c764abf99f92be82ea1eec4ee66d3d8f26236706 Mon Sep 17 00:00:00 2001 From: Salih Date: Sat, 25 Feb 2023 15:39:47 +0300 Subject: [PATCH 12/28] Update picker --- .../bootstrap/dom-event-handlers.js | 116 +++++++++++++++++- .../Localization/Resources/AbpUi/en.json | 4 +- .../Localization/Resources/AbpUi/tr.json | 4 +- 3 files changed, 116 insertions(+), 8 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 35b19292cc..64ba06ff3a 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -315,16 +315,33 @@ drops: "down", autoApply: true, autoUpdateInput: false, + showTodayButton: true, + showClearButton: true, minYear: parseInt(moment().subtract(100, 'year').locale('en').format('YYYY')), maxYear: parseInt(moment().add(100, 'year').locale('en').format('YYYY')), locale: { direction: abp.localization.currentCulture.isRightToLeft ? 'rtl' : 'ltr', + todayLabel: abp.localization.localize('Today', 'AbpUi'), + clearLabel: abp.localization.localize('Clear', 'AbpUi'), + applyLabel: abp.localization.localize('Apply', 'AbpUi'), }, + singleOpenAndClearButton: true }; - + var locale = defaultOptions.locale; $.extend(options, defaultOptions); $.extend(options, $this.data()); + if(jQuery.isEmptyObject(options.locale)) + { + options.locale = locale; + }else{ + locale = options.locale; + } $.extend(options, $this.data("options")); + if(jQuery.isEmptyObject(options.locale)) + { + options.locale = locale; + } + if(options.timePicker && options.timePicker24Hour === undefined){ options.timePicker24Hour = moment.localeData().longDateFormat('LT').indexOf('A') < 1; @@ -338,6 +355,23 @@ var dateFormat = options.dateFormat; var separator = options.separator; var defaultDateFormat = "YYYY-MM-DD"; + var singleOpenAndClearButton = options.singleOpenAndClearButton && $clearButton.length > 0 && $openButton.length > 0; + + const replaceButton = function (hasDate) { + var hiddenClass = 'd-none'; + if(singleOpenAndClearButton){ + if(hasDate){ + $openButton.addClass(hiddenClass); + $clearButton.removeClass(hiddenClass); + $clearButton.insertAfter($openButton); + }else { + $openButton.removeClass(hiddenClass); + $clearButton.addClass(hiddenClass); + $openButton.insertAfter($clearButton); + } + } + } + const getMoment = function (date) { if(!date){ return isUtc ? moment.utc() : moment(); @@ -385,9 +419,68 @@ }); } + var $todayBtn = $(''); + var $clearBtn = $(''); + + var extraButtons = []; + if (options.showTodayButton) { + extraButtons.push($todayBtn); + + $todayBtn.on('click', function () { + var today = getMoment(); + $input.data('daterangepicker').setStartDate(today); + $input.data('daterangepicker').setEndDate(today); + $input.data('daterangepicker').updateView(); + }); + } + if (options.showClearButton) { + extraButtons.push($clearBtn); + + $clearBtn.on('click', function () { + $input.val('').trigger('change'); + $dateRangePicker.hide(); + }); + } + + if (typeof options.template !== 'string' && !(options.template instanceof $)) + options.template = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
'; + $input.daterangepicker(options); + var $dateRangePicker = $input.data('daterangepicker'); + if($dateRangePicker.container.find('.drp-buttons').css('display') !== 'none'){ + + $.each(extraButtons, function (index, value) { + $dateRangePicker.container.find('.drp-buttons').prepend(value); + }); + } + else{ + var $div = $('
'); + $div.css('display', 'block'); + $.each(extraButtons, function (index, value) { + $div.prepend(value); + }); + + $div.insertAfter($dateRangePicker.container.find('.drp-buttons')); + + } + + $dateRangePicker.outsideClick = function(e) { var target = $(e.target); // if the page is clicked anywhere except within the daterangerpicker/button @@ -479,6 +572,11 @@ }); $input.on('change', function () { + if($(this).val() !== ''){ + replaceButton(true); + }else{ + replaceButton(false); + } var dates = $(this).val().split(separator); if (dates.length === 2) { startDate = getMoment(dates[0]); @@ -494,16 +592,22 @@ endDate = formatDate(endDate); } } else { - startDate = getMoment(dates[0]); - if (!startDate.isValid()) { + if(dates[0]){ + startDate = getMoment(dates[0]); + if (!startDate.isValid()) { + startDate = null; + }else{ + startDate = formatDate(startDate); + } + } + else{ startDate = null; - }else{ - startDate = formatDate(startDate); } endDate = null; } - if(!startDate){ + replaceButton(false); + $(this).val(''); $dateRangePicker.setStartDate(getMoment()); $dateRangePicker.setEndDate(getMoment()); } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json index 2a22849731..706b4ef3cd 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/en.json @@ -48,6 +48,8 @@ "Search": "Search", "ItemWillBeDeletedMessageWithFormat": "{0} will be deleted!", "ItemWillBeDeletedMessage": "This item will be deleted!", - "ManageYourAccount": "Manage your account" + "ManageYourAccount": "Manage your account", + "Today": "Today", + "Apply": "Apply" } } diff --git a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json index 67ae56793a..e122b9b531 100644 --- a/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json +++ b/framework/src/Volo.Abp.UI/Localization/Resources/AbpUi/tr.json @@ -48,6 +48,8 @@ "Search": "Arama", "ItemWillBeDeletedMessageWithFormat": "{0} silinecektir!", "ItemWillBeDeletedMessage": "Bu nesne silinecektir!", - "ManageYourAccount": "Hesap yönetimi" + "ManageYourAccount": "Hesap yönetimi", + "Today": "Bugün", + "Apply": "Uygula" } } From 22668a2a54da7cddd87a9121f9bab751c30af84b Mon Sep 17 00:00:00 2001 From: Ebicoglu Date: Thu, 9 Mar 2023 16:50:19 +0300 Subject: [PATCH 13/28] refactored --- .../Form/AbpDynamicformTagHelperService.cs | 36 +-- .../DatePicker/AbpDatePickerBaseTagHelper.cs | 7 +- .../Form/DatePicker/AbpDatePickerDrops.cs | 8 +- .../Form/DatePicker/AbpDatePickerOpens.cs | 12 +- .../AbpDatePickerTagHelperService.cs | 23 +- .../DatePicker/AbpDatePickerWeekNumbers.cs | 8 +- .../DatePicker/AbpDateRangePickerTagHelper.cs | 5 +- .../AbpDateRangePickerTagHelperService.cs | 45 ++-- .../DatePicker/DatePickerOptionsAttribute.cs | 2 +- .../DatePicker/DateRangePickerAttribute.cs | 5 +- .../Form/DatePicker/IAbpDatePickerOptions.cs | 117 ++++++--- .../bootstrap/dom-event-handlers.js | 226 +++++++++--------- 12 files changed, 285 insertions(+), 209 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs index 17383b46d6..775b19beb1 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpDynamicformTagHelperService.cs @@ -179,34 +179,37 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService(); var pickerId = modelAttribute.PickerId; - var otherModel = TagHelper.Model.ModelExplorer.Properties.SingleOrDefault(x => - x != model.ModelExplorer && x.GetAttribute()?.PickerId == pickerId); - var otherModelAttribute = otherModel?.GetAttribute(); var abpDateRangeInputTagHelper = _serviceProvider.GetRequiredService(); abpDateRangeInputTagHelper.PickerId = pickerId; abpDateRangeInputTagHelper.ViewContext = TagHelper.ViewContext; + if (modelAttribute.IsStart) { abpDateRangeInputTagHelper.AspForStart = model; - } - if (otherModelAttribute?.IsStart == false) - { - abpDateRangeInputTagHelper.AspForEnd = ModelExplorerToModelExpressionConverter(otherModel); + var otherModelExists = TryToGetOtherDateModel(model, pickerId, out var otherModel); + if (otherModelExists && otherModel.GetAttribute().IsEnd) + { + abpDateRangeInputTagHelper.AspForEnd = ModelExplorerToModelExpressionConverter(otherModel); + } } return abpDateRangeInputTagHelper; } + private bool TryToGetOtherDateModel(ModelExpression model, string pickerId, out ModelExplorer otherModel) + { + otherModel = TagHelper.Model.ModelExplorer.Properties.SingleOrDefault(x => x != model.ModelExplorer && x.GetAttribute()?.PickerId == pickerId); + return otherModel != null; + } - private bool IsDateRangeGroup(ModelExplorer modelModelExplorer) + private static bool IsDateRangeGroup(ModelExplorer modelModelExplorer) { return modelModelExplorer.GetAttribute() != null; } @@ -353,18 +356,23 @@ public class AbpDynamicFormTagHelperService : AbpTagHelperService() != null || model.ModelExplorer.GetAttribute() != null) + if (model.ModelExplorer.GetAttribute() != null || + model.ModelExplorer.GetAttribute() != null) { return true; } - - if(model.Metadata.ModelType == typeof(DateTime) || model.Metadata.ModelType == typeof(DateTime?) || model.Metadata.ModelType == typeof(DateTimeOffset) || model.Metadata.ModelType == typeof(DateTimeOffset?)) + + if (model.Metadata.ModelType == typeof(DateTime) || + model.Metadata.ModelType == typeof(DateTime?) || + model.Metadata.ModelType == typeof(DateTimeOffset) || + model.Metadata.ModelType == typeof(DateTimeOffset?)) { return true; } + return false; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs index a85a41f7e8..55cd41f999 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs @@ -9,7 +9,8 @@ public abstract class where TTagHelper : AbpDatePickerBaseTagHelper { - private IAbpDatePickerOptions _abpDatePickerOptionsImplementation; + private readonly IAbpDatePickerOptions _abpDatePickerOptionsImplementation; + public string Label { get; set; } public string LabelTooltip { get; set; } @@ -42,15 +43,11 @@ public abstract class public bool SuppressLabel { get; set; } - - - protected AbpDatePickerBaseTagHelper(AbpDatePickerBaseTagHelperService service) : base(service) { _abpDatePickerOptionsImplementation = new AbpDatePickerOptions(); } - public string PickerId { get => _abpDatePickerOptionsImplementation.PickerId; set => _abpDatePickerOptionsImplementation.PickerId = value; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs index 7e26e27c66..c61cbfec78 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerDrops.cs @@ -1,8 +1,8 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; -public enum AbpDatePickerDrops +public enum AbpDatePickerDrops : byte { - Down, - Up, - Auto + Down = 1, + Up = 2, + Auto = 3 } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs index a69ead079d..a74bf229ef 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOpens.cs @@ -1,8 +1,10 @@ -namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; +using System; -public enum AbpDatePickerOpens +namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; + +public enum AbpDatePickerOpens : byte { - Left, - Right, - Center + Left = 1, + Right = 2, + Center = 3, } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs index 8007a13a17..e5eae85c53 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerTagHelperService.cs @@ -16,14 +16,14 @@ public class AbpDatePickerTagHelperService : AbpDatePickerBaseTagHelperService l, IAbpTagHelperLocalizer tagHelperLocalizer) : base(jsonSerializer, generator, encoder, serviceProvider, l, tagHelperLocalizer) { - + } protected override TagHelperOutput TagHelperOutput { get; set; } - - [CanBeNull] + + [CanBeNull] protected virtual InputTagHelper DateTagHelper { get; set; } - + [CanBeNull] protected virtual TagHelperOutput DateTagHelperOutput { get; set; } protected override string GetPropertyName() @@ -39,12 +39,15 @@ public class AbpDatePickerTagHelperService : AbpDatePickerBaseTagHelperService { - // Start date [CanBeNull] public ModelExpression AspForStart { get; set; } - // End date [CanBeNull] public ModelExpression AspForEnd { get; set; } - public AbpDateRangePickerTagHelper(AbpDateRangePickerTagHelperService tagHelperService) : base(tagHelperService) + public AbpDateRangePickerTagHelper(AbpDateRangePickerTagHelperService tagHelperService) : + base(tagHelperService) { } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs index a869147bfd..45a083b789 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDateRangePickerTagHelperService.cs @@ -17,7 +17,8 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ { public AbpDateRangePickerTagHelperService(IJsonSerializer jsonSerializer, IHtmlGenerator generator, HtmlEncoder encoder, IServiceProvider serviceProvider, IStringLocalizer l, - IAbpTagHelperLocalizer tagHelperLocalizer) : base(jsonSerializer, generator, encoder, serviceProvider, l, + IAbpTagHelperLocalizer tagHelperLocalizer) : + base(jsonSerializer, generator, encoder, serviceProvider, l, tagHelperLocalizer) { } @@ -26,36 +27,36 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ protected override T GetAttributeAndModelExpression(out ModelExpression modelExpression) { - modelExpression = - new[] { TagHelper.AspForStart, TagHelper.AspForEnd }.FirstOrDefault(x => - x?.ModelExplorer?.GetAttribute() != null); + modelExpression = new[] { TagHelper.AspForStart, TagHelper.AspForEnd }.FirstOrDefault(x => x?.ModelExplorer?.GetAttribute() != null); return modelExpression?.ModelExplorer.GetAttribute(); } public async override Task ProcessAsync(TagHelperContext context, TagHelperOutput output) { - if (TagHelper.AspForStart != null) { - var startDateAttributes = - new TagHelperAttributeList { { "data-start-date", "true" }, { "type", "hidden" } }; - StartDateTagHelper = new InputTagHelper(Generator) { - ViewContext = TagHelper.ViewContext, For = TagHelper.AspForStart, InputTypeName = "hidden" + var startDateAttributes = new TagHelperAttributeList { { "data-start-date", "true" }, { "type", "hidden" } }; + StartDateTagHelper = new InputTagHelper(Generator) + { + ViewContext = TagHelper.ViewContext, + For = TagHelper.AspForStart, + InputTypeName = "hidden" }; - StartDateTagHelperOutput = - await StartDateTagHelper.ProcessAndGetOutputAsync(startDateAttributes, context, "input"); + StartDateTagHelperOutput = await StartDateTagHelper.ProcessAndGetOutputAsync(startDateAttributes, context, "input"); } if (TagHelper.AspForEnd != null) { var endDateAttributes = new TagHelperAttributeList { { "data-end-date", "true" }, { "type", "hidden" } }; - EndDateTagHelper = new InputTagHelper(Generator) { - ViewContext = TagHelper.ViewContext, For = TagHelper.AspForEnd,InputTypeName = "hidden" + EndDateTagHelper = new InputTagHelper(Generator) + { + ViewContext = TagHelper.ViewContext, + For = TagHelper.AspForEnd, + InputTypeName = "hidden" }; - EndDateTagHelperOutput = - await EndDateTagHelper.ProcessAndGetOutputAsync(endDateAttributes, context, "input"); + EndDateTagHelperOutput = await EndDateTagHelper.ProcessAndGetOutputAsync(endDateAttributes, context, "input"); } await base.ProcessAsync(context, output); @@ -63,16 +64,16 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ protected override TagHelperOutput TagHelperOutput { get; set; } - [CanBeNull] + [CanBeNull] protected virtual InputTagHelper StartDateTagHelper { get; set; } - [CanBeNull] + [CanBeNull] protected virtual TagHelperOutput StartDateTagHelperOutput { get; set; } - [CanBeNull] + [CanBeNull] protected virtual InputTagHelper EndDateTagHelper { get; set; } - [CanBeNull] + [CanBeNull] protected virtual TagHelperOutput EndDateTagHelperOutput { get; set; } protected override string GetPropertyName() @@ -87,13 +88,15 @@ public class AbpDateRangePickerTagHelperService : AbpDatePickerBaseTagHelperServ protected override void AddBaseTagAttributes(TagHelperAttributeList attributes) { - if (TagHelper.AspForStart != null && TagHelper.AspForStart.Model != null && + if (TagHelper.AspForStart != null && + TagHelper.AspForStart.Model != null && SupportedInputTypes.TryGetValue(TagHelper.AspForStart.Metadata.ModelType, out var convertFuncStart)) { attributes.Add("data-start-date", convertFuncStart(TagHelper.AspForStart.Model)); } - if (TagHelper.AspForEnd != null && TagHelper.AspForEnd.Model != null && + if (TagHelper.AspForEnd != null && + TagHelper.AspForEnd.Model != null && SupportedInputTypes.TryGetValue(TagHelper.AspForEnd.Metadata.ModelType, out var convertFuncEnd)) { attributes.Add("data-end-date", convertFuncEnd(TagHelper.AspForEnd.Model)); diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs index 3b2d605be4..97943d9dcf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -6,7 +6,7 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; [AttributeUsage(AttributeTargets.Property)] public class DatePickerOptionsAttribute : Attribute, IAbpDatePickerOptions { - private IAbpDatePickerOptions _abpDatePickerOptionsImplementation; + private readonly IAbpDatePickerOptions _abpDatePickerOptionsImplementation; public DatePickerOptionsAttribute() { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs index 7892df6918..04412ed4fc 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DateRangePickerAttribute.cs @@ -6,8 +6,11 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; public class DateRangePickerAttribute : Attribute { public string PickerId { get; set; } + public bool IsStart { get; set; } - + + public bool IsEnd => !IsStart; + public DateRangePickerAttribute(string pickerId, bool isStart = false) { PickerId = pickerId; diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs index 993af0c41f..9bcb5adf10 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs @@ -7,94 +7,143 @@ namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; public interface IAbpDatePickerOptions { public string PickerId { get; set; } - // Min and Max date + + /// + /// Min date allowed + /// DateTime? MinDate { get; set; } + /// + /// Max date allowed + /// DateTime? MaxDate { get; set; } - // Max span between start and end date - object? MaxSpan { get; set; } + /// + /// Max span between start and end date + /// + object MaxSpan { get; set; } - // Show dropdowns + /// + /// Show dropdowns + /// bool? ShowDropdowns { get; set; } - // Min and Max year + /// + /// Min year allowed + /// int? MinYear { get; set; } + /// + /// Max year allowed + /// int? MaxYear { get; set; } - // Show week numbers + /// + /// Show week numbers + /// AbpDatePickerWeekNumbers WeekNumbers { get; set; } - // Time picker + /// + /// Allows users to pick a time + /// bool? TimePicker { get; set; } - // Time picker increment + /// + /// The time interval allowed + /// int? TimePickerIncrement { get; set; } - // Time picker 24 hour + /// + /// Sets the time picker hour format as 12 or 24. + /// bool? TimePicker24Hour { get; set; } - // Time picker seconds + /// + /// Allows seconds selection + /// bool? TimePickerSeconds { get; set; } - // Ranges object + /// + /// Predefined date range list + /// List Ranges { get; set; } - - // Show custom range label + + /// + /// Show custom range label + /// bool? ShowCustomRangeLabel { get; set; } - - // Always show calendar + + /// + /// Always show calendars + /// bool? AlwaysShowCalendars { get; set; } - // Opens date picker on left or right or center of the input + /// + /// The horizontal location of the datepicker + /// AbpDatePickerOpens Opens { get; set; } - // Drops down or up or auto + /// + /// The vertical location of the datepicker + /// AbpDatePickerDrops Drops { get; set; } - // Button classes - [CanBeNull] + /// + /// Button CSS classes + /// + [CanBeNull] string ButtonClasses { get; set; } - // Apply class to all buttons - [CanBeNull] + /// + /// Apply class to all buttons + /// + [CanBeNull] string ApplyButtonClasses { get; set; } - // Cancel class to all buttons - [CanBeNull] + /// + /// Cancel CSS classes to all buttons + /// + [CanBeNull] string CancelButtonClasses { get; set; } - // Locale - [CanBeNull] + /// + /// Sets a custom locale + /// + [CanBeNull] object Locale { get; set; } - // Auto apply + /// + /// Applies the value when it a date is selected + /// bool? AutoApply { get; set; } - // Linked calendars + /// + /// When enabled, the two calendars displayed will always be for two sequential months (i.e. January and February), and both will be advanced when clicking the left or right arrows above the calendars. When disabled, the two calendars can be individually advanced and display any month/year. + /// bool? LinkedCalendars { get; set; } - // Auto update input + /// + /// Updates the input automatically + /// bool? AutoUpdateInput { get; set; } // Parent element - [CanBeNull] + [CanBeNull] string ParentEl { get; set; } - [CanBeNull] + [CanBeNull] string DateFormat { get; set; } bool OpenButton { get; set; } bool ClearButton { get; set; } - + bool SingleOpenAndClearButton { get; set; } bool? IsUtc { get; set; } - + bool? IsIso { get; set; } - - [CanBeNull] + + [CanBeNull] object Options { get; set; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 64ba06ff3a..3499aef9a9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -187,7 +187,7 @@ }); }); } - + abp.libs.bootstrapDateRangePicker = { packageName: "bootstrap-daterangepicker", @@ -207,6 +207,7 @@ if (options.label) { label.text(options.label) } + $container.append(label) var $datePicker = options.singleDatePicker ? $('') : $(''); $container.append($datePicker) @@ -292,19 +293,20 @@ return $container; } }; - - + + abp.dom.initializers.initializeDateRangePickers = function ($rootElement) { $rootElement .findWithSelf('abp-date-picker,abp-date-range-picker') .each(function () { var $this = $(this); - var $input = $(this).find('.input-group input[type="text"]') - if($input.data('daterangepicker')) { + var $input = $this.find('.input-group input[type="text"]') + if ($input.data('daterangepicker')) { return; } - var $openButton = $(this).find('button[data-type="open"]') - var $clearButton = $(this).find('button[data-type="clear"]') + + var $openButton = $this.find('button[data-type="open"]') + var $clearButton = $this.find('button[data-type="clear"]') var singleDatePicker = $this.is('abp-date-picker') var options = {}; options.singleDatePicker = singleDatePicker; @@ -321,29 +323,27 @@ maxYear: parseInt(moment().add(100, 'year').locale('en').format('YYYY')), locale: { direction: abp.localization.currentCulture.isRightToLeft ? 'rtl' : 'ltr', - todayLabel: abp.localization.localize('Today', 'AbpUi'), - clearLabel: abp.localization.localize('Clear', 'AbpUi'), - applyLabel: abp.localization.localize('Apply', 'AbpUi'), + todayLabel: abp.localization.localize('Today', 'AbpUi'), + clearLabel: abp.localization.localize('Clear', 'AbpUi'), + applyLabel: abp.localization.localize('Apply', 'AbpUi'), }, singleOpenAndClearButton: true }; var locale = defaultOptions.locale; $.extend(options, defaultOptions); $.extend(options, $this.data()); - if(jQuery.isEmptyObject(options.locale)) - { + if (jQuery.isEmptyObject(options.locale)) { options.locale = locale; - }else{ + } else { locale = options.locale; } + $.extend(options, $this.data("options")); - if(jQuery.isEmptyObject(options.locale)) - { + if (jQuery.isEmptyObject(options.locale)) { options.locale = locale; } - - if(options.timePicker && options.timePicker24Hour === undefined){ + if (options.timePicker && options.timePicker24Hour === undefined) { options.timePicker24Hour = moment.localeData().longDateFormat('LT').indexOf('A') < 1; } @@ -356,33 +356,35 @@ var separator = options.separator; var defaultDateFormat = "YYYY-MM-DD"; var singleOpenAndClearButton = options.singleOpenAndClearButton && $clearButton.length > 0 && $openButton.length > 0; - + const replaceButton = function (hasDate) { var hiddenClass = 'd-none'; - if(singleOpenAndClearButton){ - if(hasDate){ + + if (singleOpenAndClearButton) { + if (hasDate) { $openButton.addClass(hiddenClass); $clearButton.removeClass(hiddenClass); $clearButton.insertAfter($openButton); - }else { + } else { $openButton.removeClass(hiddenClass); $clearButton.addClass(hiddenClass); $openButton.insertAfter($clearButton); } } } - + const getMoment = function (date) { - if(!date){ + if (!date) { return isUtc ? moment.utc() : moment(); } - if(isUtc) { - return moment.utc(date,dateFormat); - }else { - return moment(date,dateFormat); + + if (isUtc) { + return moment.utc(date, dateFormat); + } else { + return moment(date, dateFormat); } } - + if (dateFormat) { options.locale = options.locale || {}; options.locale.format = dateFormat; @@ -394,25 +396,25 @@ } var startDate = options.startDate ? moment(options.startDate) : null; - if(singleDatePicker && !startDate){ + if (singleDatePicker && !startDate) { startDate = options.date ? moment(options.date) : null; } + var endDate = options.endDate ? moment(options.endDate) : null; - if (startDate) { options.startDate = startDate; } if (endDate) { options.endDate = endDate; } - - if(options.ranges){ + + if (options.ranges) { $.each(options.ranges, function (key, value) { let start = value[0]; let end; - if(value.length > 1){ + if (value.length > 1) { end = value[1]; - }else{ + } else { end = value[0]; } options.ranges[key] = [getMoment(start), getMoment(end)]; @@ -421,11 +423,11 @@ var $todayBtn = $(''); var $clearBtn = $(''); - + var extraButtons = []; if (options.showTodayButton) { extraButtons.push($todayBtn); - + $todayBtn.on('click', function () { var today = getMoment(); $input.data('daterangepicker').setStartDate(today); @@ -433,43 +435,44 @@ $input.data('daterangepicker').updateView(); }); } + if (options.showClearButton) { extraButtons.push($clearBtn); - + $clearBtn.on('click', function () { $input.val('').trigger('change'); $dateRangePicker.hide(); }); } - + if (typeof options.template !== 'string' && !(options.template instanceof $)) options.template = '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - ' ' + - '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' ' + + '
' + '
'; $input.daterangepicker(options); - + var $dateRangePicker = $input.data('daterangepicker'); - - if($dateRangePicker.container.find('.drp-buttons').css('display') !== 'none'){ - + + if ($dateRangePicker.container.find('.drp-buttons').css('display') !== 'none') { + $.each(extraButtons, function (index, value) { $dateRangePicker.container.find('.drp-buttons').prepend(value); }); } - else{ + else { var $div = $('
'); $div.css('display', 'block'); $.each(extraButtons, function (index, value) { @@ -477,14 +480,11 @@ }); $div.insertAfter($dateRangePicker.container.find('.drp-buttons')); - } - - - $dateRangePicker.outsideClick = function(e) { + + $dateRangePicker.outsideClick = function (e) { var target = $(e.target); - // if the page is clicked anywhere except within the daterangerpicker/button - // itself then call this.hide() + // if the page is clicked anywhere except within the daterangerpicker/button itself then call this.hide() if ( // ie modal dialog fix e.type == "focusin" || @@ -492,24 +492,27 @@ target.closest(this.container).length || target.closest('.calendar-table').length || target.closest($openButton).length - ) return; + ) { + return; + } + this.hide(); this.element.trigger('outsideClick.daterangepicker', this); }; - + $openButton.on('click', function () { $dateRangePicker.toggle(); }); - + const extendDateFormat = function (format) { - if(timePicker){ - if(timePicker24Hour){ - if(timePickerSeconds){ + if (timePicker) { + if (timePicker24Hour) { + if (timePickerSeconds) { format += " HH:mm:ss"; - }else{ + } else { format += " HH:mm"; } - }else { + } else { if (timePickerSeconds) { format += ' ' + " hh:mm:ss A" } else { @@ -517,33 +520,34 @@ } } } + return format; } - + defaultDateFormat = extendDateFormat(defaultDateFormat); - if(!dateFormat) { + if (!dateFormat) { dateFormat = extendDateFormat(moment.localeData().longDateFormat('L')) } - - if(!separator) { + + if (!separator) { separator = $dateRangePicker.locale.separator; } - - if(singleDatePicker){ - if(startDate){ + + if (singleDatePicker) { + if (startDate) { $input.val(startDate.format(dateFormat)); } - }else{ - if(startDate && endDate){ + } else { + if (startDate && endDate) { $input.val(startDate.format(dateFormat) + separator + endDate.format(dateFormat)); } } - + $input.on('apply.daterangepicker', function (ev, picker) { - if(singleDatePicker){ + if (singleDatePicker) { $(this).val(picker.startDate.format(dateFormat)); - }else{ + } else { $(this).val(picker.startDate.format(dateFormat) + separator + picker.endDate.format(dateFormat)); } @@ -554,6 +558,7 @@ $(this).val(''); $(this).trigger('change'); }); + $input.on('show.daterangepicker', function (ev, picker) { var momentStartDate = getMoment(startDate); var momentEndDate = getMoment(endDate); @@ -564,7 +569,6 @@ picker.setEndDate(momentEndDate); } }); - $clearButton.on('click', function () { $input.val(''); @@ -572,9 +576,9 @@ }); $input.on('change', function () { - if($(this).val() !== ''){ + if ($(this).val() !== '') { replaceButton(true); - }else{ + } else { replaceButton(false); } var dates = $(this).val().split(separator); @@ -582,91 +586,97 @@ startDate = getMoment(dates[0]); if (!startDate.isValid()) { startDate = null; - }else{ + } else { startDate = formatDate(startDate); } endDate = getMoment(dates[1]); if (!endDate.isValid()) { endDate = null; - }else{ + } else { endDate = formatDate(endDate); } } else { - if(dates[0]){ + if (dates[0]) { startDate = getMoment(dates[0]); if (!startDate.isValid()) { startDate = null; - }else{ + } else { startDate = formatDate(startDate); } } - else{ + else { startDate = null; } + endDate = null; } - if(!startDate){ + + if (!startDate) { replaceButton(false); $(this).val(''); $dateRangePicker.setStartDate(getMoment()); $dateRangePicker.setEndDate(getMoment()); } - if(!singleDatePicker){ + if (!singleDatePicker) { var input1 = $this.find("input[data-start-date]") input1.val(startDate); var input2 = $this.find("input[data-end-date]") input2.val(endDate); - }else{ + } else { var input = $this.find("input[data-date]") input.val(startDate); } - if(singleDatePicker){ + if (singleDatePicker) { $this.data('date', startDate); $input.data('date', startDate); - }else{ + } else { $this.data('startDate', startDate); $this.data('endDate', endDate); $input.data('startDate', startDate); $input.data('endDate', endDate); } }); - - function formatDate(date){ - if(date){ - if(isIso){ + + function formatDate(date) { + if (date) { + if (isIso) { return date.locale('en').format(); } return date.locale('en').format(defaultDateFormat) } + return null; } - function getFormattedStartDate (){ - if(startDate){ + + function getFormattedStartDate() { + if (startDate) { return getMoment(startDate).format(dateFormat); } + return null; } - - function getFormattedEndDate (){ - if(endDate){ + + function getFormattedEndDate() { + if (endDate) { return getMoment(endDate).format(dateFormat); } + return null; } - - if(singleDatePicker){ + + if (singleDatePicker) { $this[0].getFormattedDate = getFormattedStartDate; $input[0].getFormattedDate = getFormattedStartDate; $dateRangePicker.getFormattedDate = getFormattedStartDate; - }else{ + } else { $dateRangePicker.getFormattedStartDate = getFormattedStartDate; $dateRangePicker.getFormattedEndDate = getFormattedEndDate; - + $this[0].getFormattedStartDate = getFormattedStartDate; $this[0].getFormattedEndDate = getFormattedEndDate; - + $input[0].getFormattedStartDate = getFormattedStartDate; $input[0].getFormattedEndDate = getFormattedEndDate; } From 238cd86a087394ab00faeea2849d0414f3bcd232 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 13 Mar 2023 18:14:07 +0300 Subject: [PATCH 14/28] Update datepicker doc --- .../AspNetCore/Tag-Helpers/Form-elements.md | 113 +++++++++--------- 1 file changed, 56 insertions(+), 57 deletions(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index df8c5008ac..0275bf8030 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -10,7 +10,7 @@ See the [form elements demo page](https://bootstrap-taghelpers.abp.io/Components ## abp-input -`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of Asp.Net Core is also valid for `abp-input`. +`abp-input` tag creates a Bootstrap form input for a given c# property. It uses [ASP.NET Core Input Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) in background, so every data annotation attribute of `input` tag helper of ASP.NET Core is also valid for `abp-input`. Usage: @@ -58,49 +58,49 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes - `[TextArea()]`: Converts the input into a text area. -* `[Placeholder()]`: Sets placeholder for input. You can use a localization key directly. -* `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly. -* `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are +* `[Placeholder()]`: Sets the description are of the input. You can use a localization key directly. +* `[InputInfoText()]`: Sets text for the input. You can directly use a localization key. +* `[FormControlSize()]`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `[DisabledInput]` : Input is disabled. -* `[ReadOnlyInput]`: Input is read-only. +* `[DisabledInput]` : Sets the input as disabled. +* `[ReadOnlyInput]`: Sets the input as read-only. #### Tag Attributes -* `info`: Sets a small info text for input. You can use a localization key directly. -* `auto-focus`: If true, browser auto focuses on the element. -* `size`: Sets size of form-control wrapper element. Available values are +* `info`: Sets text for the input. You can directly use a localization key. +* `auto-focus`: It lets the browser set focus to the element when its value is true. +* `size`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `disabled`: Input is disabled. -* `readonly`: Input is read-only. -* `label`: Sets the label for input. -* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `label`: Sets the label of input. +* `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. -`asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) are also valid for `abp-input` tag helper. +`asp-format`, `name` and `value` attributes of [ASP.NET Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-input-tag-helper) are also valid for `abp-input` tag helper. ### Label & Localization -You can set label of your input in different ways: +You can set the label of the input in several ways: -- You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value"`. -- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core. +- You can use the `Label` attribute to set the label directly. This property does not automatically localize the text. To localize the label, use `label="@L["{LocalizationKey}"].Value"`. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute of ASP.NET Core. - You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys, if `label` or `[DisplayName]` attributes are not set. ## abp-select -`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [Asp.Net Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of Asp.Net Core is also valid for `abp-select`. +`abp-select` tag creates a Bootstrap form select for a given c# property. It uses [ASP.NET Core Select Tag Helper](https://docs.microsoft.com/tr-tr/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-3.1#the-select-tag-helper) in background, so every data annotation attribute of `select` tag helper of ASP.NET Core is also valid for `abp-select`. `abp-select` tag needs a list of `Microsoft.AspNetCore.Mvc.Rendering.SelectListItem ` to work. It can be provided by `asp-items` attriube on the tag or `[SelectItems()]` attribute on c# property. (if you are using [abp-dynamic-form](Dynamic-forms.md), c# attribute is the only way.) @@ -170,14 +170,14 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes * `[SelectItems()]`: Sets the select data. Parameter should be the name of the data list. (see example above) -- `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly. -- `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are +- `[InputInfoText()]`: Sets text for the input. You can directly use a localization key. +- `[FormControlSize()]`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` @@ -186,21 +186,21 @@ You can set some of the attributes on your c# property, or directly on html tag. #### Tag Attributes - `asp-items`: Sets the select data. This Should be a list of SelectListItem. -- `info`: Sets a small info text for input. You can use a localization key directly. -- `size`: Sets size of form-control wrapper element. Available values are +- `info`: Sets text for the input. You can directly use a localization key. +- `size`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -- `label`: Sets the label for input. -- `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. +- `label`: Sets the label of input. +- `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. ### Label & Localization -You can set label of your input in different ways: +You can set the label of the input in several ways: - You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value".` -- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute of ASP.NET Core. - You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys. Localizations of combobox values are set by `abp-select` for **Enum** property. It searches for "{EnumTypeName}.{EnumPropertyName}" or "{EnumPropertyName}" localization keys. For instance, in the example above, it will use "CarType.StationWagon" or "StationWagon" keys for localization when it localizes combobox values. @@ -251,7 +251,7 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes @@ -298,47 +298,47 @@ Model: ### Attributes -You can set some of the attributes on your c# property, or directly on html tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. +You can set some of the attributes on your c# property, or directly on HTML tag. If you are going to use this property in a [abp-dynamic-form](Dynamic-forms.md), then you can only set these properties via property attributes. #### Property Attributes -* `[Placeholder()]`: Sets placeholder for input. You can use a localization key directly. -* `[InputInfoText()]`: Sets a small info text for input. You can use a localization key directly. -* `[FormControlSize()]`: Sets size of form-control wrapper element. Available values are +* `[Placeholder()]`: Sets the description are of the input. You can use a localization key directly. +* `[InputInfoText()]`: Sets text for the input. You can directly use a localization key. +* `[FormControlSize()]`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `[DisabledInput]` : Input is disabled. -* `[ReadOnlyInput]`: Input is read-only. -- `[DatePickerOptions()]`: Sets the options of datepicker. You can use a localization key directly. See [datepicker options](https://www.daterangepicker.com/#options) for more information.) +* `[DisabledInput]` : Sets the input as disabled. +* `[ReadOnlyInput]`: Sets the input as read-only. +- `[DatePickerOptions()]`: Sets the predefined options of the date picker. See the available [datepicker options](https://www.daterangepicker.com/#options). You can use a localization key directly. ##### abp-date-picker -`[DatePicker]` : Date picker is enabled. +`[DatePicker]` : Sets the input as datepicker. Especially for string properties. ##### abp-date-range-picker -`[DateRangePicker()]` : Sets the picker id for date range picker. This is used to link start and end date pickers. And sets this property is start date or end date. +`[DateRangePicker()]` : Sets the picker id for the date range picker. You can set the property as a start date by setting IsStart=true or leave it as default/false to set it as an end date. #### Tag Attributes -* `info`: Sets a small info text for input. You can use a localization key directly. -* `auto-focus`: If true, browser auto focuses on the element. -* `size`: Sets size of form-control wrapper element. Available values are +* `info`: Sets text for the input. You can directly use a localization key. +* `auto-focus`: It lets the browser set focus to the element when its value is true. +* `size`: Sets the size of the form-control wrapper element. Available values are - `AbpFormControlSize.Default` - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `disabled`: Input is disabled. -* `readonly`: Input is read-only. -* `label`: Sets the label for input. -* `display-required-symbol`: Adds the required symbol (*) to label if input is required. Default `True`. -* `open-button`: If true, a button will be added to open datepicker. Default `True`. -* `clear-button`: If true, a button will be added to clear datepicker. Default `True`. -* `is-utc`: If true, datepicker will use UTC date. Default `False`. -* `is-iso`: If true, datepicker will use ISO date. Default `False`. -* `date-format`: Sets the date format. Default your culture's date format. (JS format) -* `date-separator`: Sets the range date separator. Default `-`. -* Other attributes will be added to the input element and [datepicker options](https://www.daterangepicker.com/#options). +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `label`: Sets the label of input. +* `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. +* `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. +* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True` +* `is-utc`: Converts the date to UTC when its `True`. The default value is `False`. +* `is-iso`: Converts the date to ISO format when its `True`. The default value is `False`. +* `date-format`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. +* `date-separator`: Sets a character to separate start and end dates. The default value is `-` +* Other non-mapped attributes will be automatically added to the input element as is. See the available [datepicker options](https://www.daterangepicker.com/#options). Eg: `data-start-date="2020-01-01"` ##### abp-date-picker @@ -351,9 +351,8 @@ You can set some of the attributes on your c# property, or directly on html tag. ### Label & Localization -You can set label of your input in different ways: - -- You can use `Label` attribute and directly set the label. But it doesn't auto localize your localization key. So use it as `label="@L["{LocalizationKey}"].Value"`. -- You can set it using `[Display(name="{LocalizationKey}")]` attribute of Asp.Net Core. -- You can just let **abp** find the localization key for the property. It will try to find "DisplayName:{PropertyName}" or "{PropertyName}" localization keys, if `label` or `[DisplayName]` attributes are not set. +You can set the label of the input in several ways: +- You can use the `Label` attribute to set the label directly. This property does not automatically localize the text. To localize the label, use `label="@L["{LocalizationKey}"].Value"`. +- You can set it using `[Display(name="{LocalizationKey}")]` attribute ASP.NET Core. +- You can just let **abp** find the localization key for the property. If the `label` or `[DisplayName]` attributes are not set, it tries to find the localization by convention. For example `DisplayName:{YourPropertyName}` or `{YourPropertyName}`. If your property name is FullName, it will search for `DisplayName:FullName` or `{FullName}`. \ No newline at end of file From 3cf5cfdddd8cbbca7bf5bf9341e09d5c44a0a335 Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 13 Mar 2023 18:16:06 +0300 Subject: [PATCH 15/28] Add today button classes, replace cancel button to clear button and add options summary --- .../DatePicker/AbpDatePickerBaseTagHelper.cs | 11 +++- .../AbpDatePickerBaseTagHelperService.cs | 9 ++- .../Form/DatePicker/AbpDatePickerOptions.cs | 3 +- .../DatePicker/DatePickerOptionsAttribute.cs | 11 +++- .../Form/DatePicker/IAbpDatePickerOptions.cs | 59 +++++++++++-------- 5 files changed, 60 insertions(+), 33 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs index 55cd41f999..10923f25af 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelper.cs @@ -138,14 +138,19 @@ public abstract class set => _abpDatePickerOptionsImplementation.ButtonClasses = value; } + public string TodayButtonClasses { + get => _abpDatePickerOptionsImplementation.TodayButtonClasses; + set => _abpDatePickerOptionsImplementation.TodayButtonClasses = value; + } + public string ApplyButtonClasses { get => _abpDatePickerOptionsImplementation.ApplyButtonClasses; set => _abpDatePickerOptionsImplementation.ApplyButtonClasses = value; } - public string CancelButtonClasses { - get => _abpDatePickerOptionsImplementation.CancelButtonClasses; - set => _abpDatePickerOptionsImplementation.CancelButtonClasses = value; + public string ClearButtonClasses { + get => _abpDatePickerOptionsImplementation.ClearButtonClasses; + set => _abpDatePickerOptionsImplementation.ClearButtonClasses = value; } public object Locale { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index 67b20c3c5e..b9244ff326 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -302,9 +302,14 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp attrList.Add("data-apply-button-classes", options.ApplyButtonClasses); } - if (!options.CancelButtonClasses.IsNullOrEmpty()) + if (!options.ClearButtonClasses.IsNullOrEmpty()) { - attrList.Add("data-cancel-button-classes", options.CancelButtonClasses); + attrList.Add("data-clear-button-classes", options.ClearButtonClasses); + } + + if (!options.TodayButtonClasses.IsNullOrEmpty()) + { + attrList.Add("data-today-button-classes", options.TodayButtonClasses); } if (options.AutoApply != null) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs index 4dfdd3b86a..15b4e2003d 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerOptions.cs @@ -23,8 +23,9 @@ public class AbpDatePickerOptions : IAbpDatePickerOptions public AbpDatePickerOpens Opens { get; set; } = AbpDatePickerOpens.Center; public AbpDatePickerDrops Drops { get; set; } = AbpDatePickerDrops.Down; public string ButtonClasses { get; set; } + public string TodayButtonClasses { get; set; } public string ApplyButtonClasses { get; set; } - public string CancelButtonClasses { get; set; } + public string ClearButtonClasses { get; set; } public object Locale { get; set; } public bool? AutoApply { get; set; } public bool? LinkedCalendars { get; set; } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs index 97943d9dcf..8b64b28d05 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -103,14 +103,19 @@ public class DatePickerOptionsAttribute : Attribute, IAbpDatePickerOptions set => _abpDatePickerOptionsImplementation.ButtonClasses = value; } + public string TodayButtonClasses { + get => _abpDatePickerOptionsImplementation.TodayButtonClasses; + set => _abpDatePickerOptionsImplementation.TodayButtonClasses = value; + } + public string ApplyButtonClasses { get => _abpDatePickerOptionsImplementation.ApplyButtonClasses; set => _abpDatePickerOptionsImplementation.ApplyButtonClasses = value; } - public string CancelButtonClasses { - get => _abpDatePickerOptionsImplementation.CancelButtonClasses; - set => _abpDatePickerOptionsImplementation.CancelButtonClasses = value; + public string ClearButtonClasses { + get => _abpDatePickerOptionsImplementation.ClearButtonClasses; + set => _abpDatePickerOptionsImplementation.ClearButtonClasses = value; } public object Locale { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs index 9bcb5adf10..118c409da9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/IAbpDatePickerOptions.cs @@ -19,118 +19,126 @@ public interface IAbpDatePickerOptions DateTime? MaxDate { get; set; } /// - /// Max span between start and end date + /// The maximum span between the selected start and end dates. Can have any property you can add to a moment object (i.e. days, months) /// object MaxSpan { get; set; } /// - /// Show dropdowns + /// Show year and month select boxes above calendars to jump to a specific month and year. /// bool? ShowDropdowns { get; set; } /// - /// Min year allowed + /// The minimum year shown in the dropdowns when showDropdowns is set to true. /// int? MinYear { get; set; } /// - /// Max year allowed + /// The maximum year shown in the dropdowns when showDropdowns is set to true. /// int? MaxYear { get; set; } /// - /// Show week numbers + /// Show week numbers at the start of each week on the calendars. /// AbpDatePickerWeekNumbers WeekNumbers { get; set; } /// - /// Allows users to pick a time + /// Adds select boxes to choose times in addition to dates. /// bool? TimePicker { get; set; } /// - /// The time interval allowed + /// Increment of the minutes selection list for times (i.e. 30 to allow only selection of times ending in 0 or 30). /// int? TimePickerIncrement { get; set; } /// - /// Sets the time picker hour format as 12 or 24. + /// Use 24-hour instead of 12-hour times, removing the AM/PM selection. /// bool? TimePicker24Hour { get; set; } /// - /// Allows seconds selection + /// Show seconds in the timePicker. /// bool? TimePickerSeconds { get; set; } /// - /// Predefined date range list + /// Set predefined date ranges the user can select from. Each key is the label for the range, and its value an array with two dates representing the bounds of the range. /// List Ranges { get; set; } /// - /// Show custom range label + /// Displays "Custom Range" at the end of the list of predefined ranges, when the ranges option is used. This option will be highlighted whenever the current date range selection does not match one of the predefined ranges. Clicking it will display the calendars to select a new range. /// bool? ShowCustomRangeLabel { get; set; } /// - /// Always show calendars + /// Normally, if you use the ranges option to specify pre-defined date ranges, calendars for choosing a custom date range are not shown until the user clicks "Custom Range". When this option is set to true, the calendars for choosing a custom date range are always shown instead. /// bool? AlwaysShowCalendars { get; set; } /// - /// The horizontal location of the datepicker + /// Whether the picker appears aligned to the left, to the right, or centered under the HTML element it's attached to. /// AbpDatePickerOpens Opens { get; set; } /// - /// The vertical location of the datepicker + /// Whether the picker appears below (default) or above the HTML element it's attached to. /// AbpDatePickerDrops Drops { get; set; } /// - /// Button CSS classes + /// CSS class names that will be added to both the today, clear, and apply buttons. /// [CanBeNull] string ButtonClasses { get; set; } /// - /// Apply class to all buttons + /// CSS class names that will be added only to the today button. + /// + [CanBeNull] + string TodayButtonClasses { get; set; } + + /// + /// CSS class names that will be added only to the apply button. /// [CanBeNull] string ApplyButtonClasses { get; set; } /// - /// Cancel CSS classes to all buttons + /// CSS class names that will be added only to the clear button. /// [CanBeNull] - string CancelButtonClasses { get; set; } + string ClearButtonClasses { get; set; } /// - /// Sets a custom locale + /// Allows you to provide localized strings for buttons and labels, customize the date format, and change the first day of week for the calendars. /// [CanBeNull] object Locale { get; set; } /// - /// Applies the value when it a date is selected + /// Hide the apply button, and automatically apply a new date range as soon as two dates are clicked. /// bool? AutoApply { get; set; } /// - /// When enabled, the two calendars displayed will always be for two sequential months (i.e. January and February), and both will be advanced when clicking the left or right arrows above the calendars. When disabled, the two calendars can be individually advanced and display any month/year. + /// When enabled, the two calendars displayed will always be for two sequential months (i.e. January and February), and both will be advanced when clicking the left or right arrows above the calendars. When disabled, the two calendars can be individually advanced and display any month/year. /// bool? LinkedCalendars { get; set; } /// - /// Updates the input automatically + /// Indicates whether the date range picker should automatically update the value of the input element it's attached to at initialization and when the selected dates change. /// bool? AutoUpdateInput { get; set; } - // Parent element + /// + /// jQuery selector of the parent element that the date range picker will be added to, if not provided this will be 'body' + /// [CanBeNull] string ParentEl { get; set; } - + [CanBeNull] string DateFormat { get; set; } @@ -144,6 +152,9 @@ public interface IAbpDatePickerOptions bool? IsIso { get; set; } + /// + /// Other non-mapped attributes will be automatically added to the input element as is. + /// [CanBeNull] object Options { get; set; } } \ No newline at end of file From 44864db332aa4206692ccfc49a381a059f0347df Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 13 Mar 2023 18:16:31 +0300 Subject: [PATCH 16/28] refactor initializeDateRangePickers method --- .../bootstrap/dom-event-handlers.js | 527 ++++++++++-------- 1 file changed, 290 insertions(+), 237 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 3499aef9a9..bbc26e4e1f 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -296,254 +296,317 @@ abp.dom.initializers.initializeDateRangePickers = function ($rootElement) { - $rootElement - .findWithSelf('abp-date-picker,abp-date-range-picker') - .each(function () { - var $this = $(this); - var $input = $this.find('.input-group input[type="text"]') - if ($input.data('daterangepicker')) { - return; - } - - var $openButton = $this.find('button[data-type="open"]') - var $clearButton = $this.find('button[data-type="clear"]') - var singleDatePicker = $this.is('abp-date-picker') - var options = {}; - options.singleDatePicker = singleDatePicker; - - var defaultOptions = { - showDropdowns: true, - opens: "center", - drops: "down", - autoApply: true, - autoUpdateInput: false, - showTodayButton: true, - showClearButton: true, - minYear: parseInt(moment().subtract(100, 'year').locale('en').format('YYYY')), - maxYear: parseInt(moment().add(100, 'year').locale('en').format('YYYY')), - locale: { - direction: abp.localization.currentCulture.isRightToLeft ? 'rtl' : 'ltr', - todayLabel: abp.localization.localize('Today', 'AbpUi'), - clearLabel: abp.localization.localize('Clear', 'AbpUi'), - applyLabel: abp.localization.localize('Apply', 'AbpUi'), - }, - singleOpenAndClearButton: true - }; - var locale = defaultOptions.locale; - $.extend(options, defaultOptions); - $.extend(options, $this.data()); - if (jQuery.isEmptyObject(options.locale)) { - options.locale = locale; - } else { - locale = options.locale; - } - - $.extend(options, $this.data("options")); - if (jQuery.isEmptyObject(options.locale)) { - options.locale = locale; - } + function setOptions (options, $datePickerElement, singleDatePicker) { + + options.singleDatePicker = singleDatePicker; + + var defaultOptions = { + showDropdowns: true, + opens: "center", + drops: "down", + autoApply: true, + autoUpdateInput: false, + showTodayButton: true, + showClearButton: true, + minYear: parseInt(moment().subtract(100, 'year').locale('en').format('YYYY')), + maxYear: parseInt(moment().add(100, 'year').locale('en').format('YYYY')), + locale: { + direction: abp.localization.currentCulture.isRightToLeft ? 'rtl' : 'ltr', + todayLabel: abp.localization.localize('Today', 'AbpUi'), + clearLabel: abp.localization.localize('Clear', 'AbpUi'), + applyLabel: abp.localization.localize('Apply', 'AbpUi'), + }, + singleOpenAndClearButton: true + }; + var locale = defaultOptions.locale; + $.extend(options, defaultOptions); + $.extend(options, $datePickerElement.data()); + if ($.isEmptyObject(options.locale)) { + options.locale = locale; + } else { + locale = options.locale; + } - if (options.timePicker && options.timePicker24Hour === undefined) { - options.timePicker24Hour = moment.localeData().longDateFormat('LT').indexOf('A') < 1; - } + $.extend(options, $datePickerElement.data("options")); + if ($.isEmptyObject(options.locale)) { + options.locale = locale; + } - var isUtc = options.isUtc; - var isIso = options.isIso; - var timePicker = options.timePicker; - var timePicker24Hour = options.timePicker24Hour; - var timePickerSeconds = options.timePickerSeconds; - var dateFormat = options.dateFormat; - var separator = options.separator; - var defaultDateFormat = "YYYY-MM-DD"; - var singleOpenAndClearButton = options.singleOpenAndClearButton && $clearButton.length > 0 && $openButton.length > 0; + if (options.timePicker && options.timePicker24Hour === undefined) { + options.timePicker24Hour = moment.localeData().longDateFormat('LT').indexOf('A') < 1; + } - const replaceButton = function (hasDate) { - var hiddenClass = 'd-none'; - - if (singleOpenAndClearButton) { - if (hasDate) { - $openButton.addClass(hiddenClass); - $clearButton.removeClass(hiddenClass); - $clearButton.insertAfter($openButton); - } else { - $openButton.removeClass(hiddenClass); - $clearButton.addClass(hiddenClass); - $openButton.insertAfter($clearButton); - } - } - } + if (options.dateFormat) { + options.locale = options.locale || {}; + options.locale.format = options.dateFormat; + } - const getMoment = function (date) { - if (!date) { - return isUtc ? moment.utc() : moment(); - } + if (options.separator) { + options.locale = options.locale || {}; + options.locale.separator = options.separator; + } - if (isUtc) { - return moment.utc(date, dateFormat); + if (options.ranges) { + $.each(options.ranges, function (key, value) { + let start = value[0]; + let end; + if (value.length > 1) { + end = value[1]; } else { - return moment(date, dateFormat); + end = value[0]; } - } + options.ranges[key] = [getMoment(start, options), getMoment(end, options.isUtc)]; + }); + } - if (dateFormat) { - options.locale = options.locale || {}; - options.locale.format = dateFormat; - } + if (typeof options.template !== 'string' && !(options.template instanceof $)) + options.template = + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + '
' + + ' ' + + '
' + + '
'; + } - if (separator) { - options.locale = options.locale || {}; - options.locale.separator = separator; - } + function replaceOpenButton (hasDate,singleOpenAndClearButton, $openButton, $clearButton) { + var hiddenClass = 'd-none'; - var startDate = options.startDate ? moment(options.startDate) : null; - if (singleDatePicker && !startDate) { - startDate = options.date ? moment(options.date) : null; + if (singleOpenAndClearButton) { + if (hasDate) { + $openButton.addClass(hiddenClass); + $clearButton.removeClass(hiddenClass); + $clearButton.insertAfter($openButton); + } else { + $openButton.removeClass(hiddenClass); + $clearButton.addClass(hiddenClass); + $openButton.insertAfter($clearButton); } + } + } - var endDate = options.endDate ? moment(options.endDate) : null; - if (startDate) { - options.startDate = startDate; - } - if (endDate) { - options.endDate = endDate; - } + function getMoment (date, options, dateFormat) { + var isUtc = options.isUtc; + dateFormat = dateFormat || options.dateFormat; + if (!date) { + return isUtc ? moment.utc() : moment(); + } - if (options.ranges) { - $.each(options.ranges, function (key, value) { - let start = value[0]; - let end; - if (value.length > 1) { - end = value[1]; - } else { - end = value[0]; - } - options.ranges[key] = [getMoment(start), getMoment(end)]; - }); + if (isUtc) { + return moment.utc(date, dateFormat); + } else { + return moment(date, dateFormat); + } + } + + function getStartDate(options, startDate){ + startDate = startDate ? startDate : options.startDate; + startDate = startDate ? getMoment(startDate, options) : null; + if (options.singleDatePicker && !startDate) { + startDate = options.date ? getMoment(options.date, options) : null; + } + + if(startDate && startDate.isValid()){ + return startDate; + } + + return null; + } + + function getEndDate(options, endDate){ + if (options.singleDatePicker) { + return null; + } + endDate = endDate ? endDate : options.endDate; + endDate = endDate ? getMoment(endDate, options) : null; + + if(endDate && endDate.isValid()){ + return endDate; + } + + return null; + } + + function getTodayButton(options, $input){ + if (options.showTodayButton) { + var $todayBtn = $(''); + if(options.todayButtonClasses){ + $todayBtn.addClass(options.todayButtonClasses); + }else{ + $todayBtn.addClass('btn-default'); } - var $todayBtn = $(''); - var $clearBtn = $(''); - - var extraButtons = []; - if (options.showTodayButton) { - extraButtons.push($todayBtn); - - $todayBtn.on('click', function () { - var today = getMoment(); - $input.data('daterangepicker').setStartDate(today); - $input.data('daterangepicker').setEndDate(today); - $input.data('daterangepicker').updateView(); - }); + $todayBtn.on('click', function () { + var today = getMoment(undefined, options); + $input.data('daterangepicker').setStartDate(today); + $input.data('daterangepicker').setEndDate(today); + $input.data('daterangepicker').updateView(); + }); + + return $todayBtn; + } + + return null; + } + + function getClearButton(options, $input, $dateRangePicker){ + if (options.showClearButton) { + var $clearBtn = $(''); + if(options.clearButtonClasses){ + $clearBtn.addClass(options.clearButtonClasses); + }else{ + $clearBtn.addClass('btn-default'); } + $clearBtn.on('click', function () { + $input.val('').trigger('change'); + $dateRangePicker.hide(); + }); + + return $clearBtn; + } + return null; + } + + function addExtraButtons(options, $dateRangePicker, $input) { + var extraButtons = [getTodayButton(options, $input), getClearButton(options, $input, $dateRangePicker)]; + if ($dateRangePicker.container.find('.drp-buttons').css('display') !== 'none') { - if (options.showClearButton) { - extraButtons.push($clearBtn); + $.each(extraButtons, function (index, value) { + $dateRangePicker.container.find('.drp-buttons').prepend(value); + }); + } else { + var $div = $('
'); + $div.css('display', 'block'); + $.each(extraButtons, function (index, value) { + $div.prepend(value); + }); - $clearBtn.on('click', function () { - $input.val('').trigger('change'); - $dateRangePicker.hide(); - }); + $div.insertAfter($dateRangePicker.container.find('.drp-buttons')); + } + } + + function addOpenButtonClick($openButton, $dateRangePicker){ + if(!$openButton){ + return; + } + $dateRangePicker.outsideClick = function (e) { + var target = $(e.target); + // if the page is clicked anywhere except within the daterangerpicker/button itself then call this.hide() + if ( + // ie modal dialog fix + e.type == "focusin" || + target.closest(this.element).length || + target.closest(this.container).length || + target.closest('.calendar-table').length || + target.closest($openButton).length + ) { + return; } - if (typeof options.template !== 'string' && !(options.template instanceof $)) - options.template = - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - '
' + - ' ' + - '
' + - '
'; - - $input.daterangepicker(options); - - var $dateRangePicker = $input.data('daterangepicker'); + this.hide(); + this.element.trigger('outsideClick.daterangepicker', this); + }; - if ($dateRangePicker.container.find('.drp-buttons').css('display') !== 'none') { + $openButton.on('click', function () { + $dateRangePicker.toggle(); + }); + } - $.each(extraButtons, function (index, value) { - $dateRangePicker.container.find('.drp-buttons').prepend(value); - }); + function extendDateFormat (format,options) { + if (options.timePicker) { + if (options.timePicker24Hour) { + if (options.timePickerSeconds) { + format += " HH:mm:ss"; + } else { + format += " HH:mm"; + } + } else { + if (options.timePickerSeconds) { + format += ' ' + " hh:mm:ss A" + } else { + format += " hh:mm A"; + } } - else { - var $div = $('
'); - $div.css('display', 'block'); - $.each(extraButtons, function (index, value) { - $div.prepend(value); - }); + } - $div.insertAfter($dateRangePicker.container.find('.drp-buttons')); + return format; + } + + function fillInput($input, startDate, endDate, options) { + if (options.singleDatePicker) { + if (startDate) { + $input.val(startDate.format(options.dateFormat)); + } + } else { + if (startDate && endDate) { + $input.val(startDate.format(options.dateFormat) + options.separator + endDate.format(options.dateFormat)); + } + } + } + + $rootElement + .findWithSelf('abp-date-picker,abp-date-range-picker') + .each(function () { + var $this = $(this); + var $input = $this.find('.input-group input[type="text"]') + if ($input.data('daterangepicker')) { + return; } - $dateRangePicker.outsideClick = function (e) { - var target = $(e.target); - // if the page is clicked anywhere except within the daterangerpicker/button itself then call this.hide() - if ( - // ie modal dialog fix - e.type == "focusin" || - target.closest(this.element).length || - target.closest(this.container).length || - target.closest('.calendar-table').length || - target.closest($openButton).length - ) { - return; - } + var $openButton = $this.find('button[data-type="open"]') + var $clearButton = $this.find('button[data-type="clear"]') + var singleDatePicker = $this.is('abp-date-picker') + var options = {}; + + setOptions(options, $this, singleDatePicker); - this.hide(); - this.element.trigger('outsideClick.daterangepicker', this); - }; + var isIso = options.isIso; + var dateFormat = options.dateFormat; + var separator = options.separator; + var defaultDateFormat = extendDateFormat("YYYY-MM-DD", options); + + var singleOpenAndClearButton = options.singleOpenAndClearButton && $clearButton.length > 0 && $openButton.length > 0; + + var startDate = getStartDate(options); - $openButton.on('click', function () { - $dateRangePicker.toggle(); - }); + var endDate = getEndDate(options); + if (startDate) { + options.startDate = startDate; + } + if (endDate) { + options.endDate = endDate; + } - const extendDateFormat = function (format) { - if (timePicker) { - if (timePicker24Hour) { - if (timePickerSeconds) { - format += " HH:mm:ss"; - } else { - format += " HH:mm"; - } - } else { - if (timePickerSeconds) { - format += ' ' + " hh:mm:ss A" - } else { - format += " hh:mm A"; - } - } - } + $input.daterangepicker(options); - return format; - } + var $dateRangePicker = $input.data('daterangepicker'); - defaultDateFormat = extendDateFormat(defaultDateFormat); + addExtraButtons(options, $dateRangePicker, $input); + addOpenButtonClick($openButton, $dateRangePicker); + if (!dateFormat) { - dateFormat = extendDateFormat(moment.localeData().longDateFormat('L')) + dateFormat = extendDateFormat(moment.localeData().longDateFormat('L'), options); + options.dateFormat = dateFormat; } if (!separator) { separator = $dateRangePicker.locale.separator; + options.separator = separator; } - if (singleDatePicker) { - if (startDate) { - $input.val(startDate.format(dateFormat)); - } - } else { - if (startDate && endDate) { - $input.val(startDate.format(dateFormat) + separator + endDate.format(dateFormat)); - } + if(options.autoUpdateInput){ + fillInput($input, startDate, endDate, options); } - + $input.on('apply.daterangepicker', function (ev, picker) { if (singleDatePicker) { $(this).val(picker.startDate.format(dateFormat)); @@ -560,8 +623,8 @@ }); $input.on('show.daterangepicker', function (ev, picker) { - var momentStartDate = getMoment(startDate); - var momentEndDate = getMoment(endDate); + var momentStartDate = getMoment(startDate, options); + var momentEndDate = getMoment(endDate, options); if (momentStartDate.isValid()) { picker.setStartDate(momentStartDate); } @@ -575,47 +638,35 @@ $input.trigger('change'); }); + var firstTrigger = true; $input.on('change', function () { if ($(this).val() !== '') { - replaceButton(true); + replaceOpenButton(true, singleOpenAndClearButton, $openButton, $clearButton); } else { - replaceButton(false); + replaceOpenButton(false, singleOpenAndClearButton, $openButton, $clearButton); } var dates = $(this).val().split(separator); if (dates.length === 2) { - startDate = getMoment(dates[0]); - if (!startDate.isValid()) { - startDate = null; - } else { - startDate = formatDate(startDate); - } - endDate = getMoment(dates[1]); - if (!endDate.isValid()) { - endDate = null; - } else { - endDate = formatDate(endDate); - } + startDate = formatDate(getStartDate(options, dates[0])); + endDate = formatDate(getEndDate(options, dates[1])); } else { if (dates[0]) { - startDate = getMoment(dates[0]); - if (!startDate.isValid()) { - startDate = null; - } else { - startDate = formatDate(startDate); - } + startDate = formatDate(getStartDate(options, dates[0])); } else { - startDate = null; + if(!firstTrigger){ + startDate = null; + } } - endDate = null; + if(!firstTrigger){ + endDate = null; + } } if (!startDate) { - replaceButton(false); + replaceOpenButton(false, singleOpenAndClearButton, $openButton, $clearButton); $(this).val(''); - $dateRangePicker.setStartDate(getMoment()); - $dateRangePicker.setEndDate(getMoment()); } if (!singleDatePicker) { @@ -637,6 +688,8 @@ $input.data('startDate', startDate); $input.data('endDate', endDate); } + + firstTrigger = false; }); function formatDate(date) { @@ -652,7 +705,7 @@ function getFormattedStartDate() { if (startDate) { - return getMoment(startDate).format(dateFormat); + return getMoment(startDate, options).format(dateFormat); } return null; @@ -660,7 +713,7 @@ function getFormattedEndDate() { if (endDate) { - return getMoment(endDate).format(dateFormat); + return getMoment(endDate, options).format(dateFormat); } return null; From 5df7a938fbc4a9f3e4ab89972859b233fccee34c Mon Sep 17 00:00:00 2001 From: Salih Date: Mon, 20 Mar 2023 13:54:30 +0300 Subject: [PATCH 17/28] Fix AbpDatePicker options attribute --- .../AspNetCore/Tag-Helpers/Form-elements.md | 28 ++- .../AbpDatePickerBaseTagHelperService.cs | 12 +- .../Form/DatePicker/AbpDatePickerRange.cs | 43 ++++ .../DatePicker/DatePickerOptionsAttribute.cs | 194 +++--------------- .../bootstrap/dom-event-handlers.js | 5 +- 5 files changed, 106 insertions(+), 176 deletions(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 0275bf8030..9140858c11 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -271,6 +271,7 @@ Usage: ````xml + ```` Model: @@ -280,9 +281,13 @@ Model: { public SampleModel MyModel { get; set; } + public DynamicForm DynamicFormExample { get; set; } + public void OnGet() { MyModel = new SampleModel(); + + DynamicFormExample = new DynamicForm(); } public class SampleModel @@ -293,6 +298,27 @@ Model: public DateTime MyDateRangeEnd { get; set; } } + + public class DynamicForm + { + [DateRangePicker("MyPicker",true)] + public DateTime StartDate { get; set; } + + [DateRangePicker("MyPicker",false)] + [DatePickerOptions(nameof(DatePickerOptions))] + public DateTime EndDate { get; set; } + + public DateTime DateTime { get; set; } + + public DynamicForm() + { + StartDate = DateTime.Now; + EndDate = DateTime.Now; + DateTime = DateTime.Now; + } + } + + public AbpDatePickerOptions DatePickerOptions { get; set; } } ```` @@ -311,7 +337,7 @@ You can set some of the attributes on your c# property, or directly on HTML tag. - `AbpFormControlSize.Large` * `[DisabledInput]` : Sets the input as disabled. * `[ReadOnlyInput]`: Sets the input as read-only. -- `[DatePickerOptions()]`: Sets the predefined options of the date picker. See the available [datepicker options](https://www.daterangepicker.com/#options). You can use a localization key directly. +- `[DatePickerOptions()]`: Sets the predefined options of the date picker. Parameter should be the name of the options property (see example above). See the available [datepicker options](https://www.daterangepicker.com/#options). You can use a localization key directly. ##### abp-date-picker `[DatePicker]` : Sets the input as datepicker. Especially for string properties. diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index b9244ff326..dbcd4e23ac 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -217,6 +217,12 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp protected TagHelperAttributeList ConvertDatePickerOptionsToAttributeList(IAbpDatePickerOptions options) { var attrList = new TagHelperAttributeList(); + + if(options == null) + { + return attrList; + } + if (options.Locale != null) { attrList.Add("data-locale", JsonSerializer.Serialize(options.Locale)); @@ -420,10 +426,10 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp attrList.Add(attr); } - var optionsAttribute = GetAttribute(); - if(optionsAttribute != null) + var optionsAttribute = GetAttributeAndModelExpression(out var modelExpression); + if (optionsAttribute != null) { - foreach (var attr in ConvertDatePickerOptionsToAttributeList(optionsAttribute)) + foreach (var attr in ConvertDatePickerOptionsToAttributeList(optionsAttribute.GetDatePickerOptions(modelExpression.ModelExplorer))) { attrList.Add(attr); } diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs index 727110c56c..eea3d2ad31 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerRange.cs @@ -8,6 +8,49 @@ public class AbpDatePickerRange private readonly List _dates = new List(); public string Label { get; set; } public IReadOnlyList Dates => _dates; + + public AbpDatePickerRange() + { + + } + public AbpDatePickerRange(string label, DateTime start, DateTime end) + { + Label = label; + AddDate(start); + AddDate(end); + } + + public AbpDatePickerRange(string label, DateTime date) + { + Label = label; + AddDate(date); + } + + public AbpDatePickerRange(string label, DateTimeOffset start, DateTimeOffset end) + { + Label = label; + AddDate(start); + AddDate(end); + } + + public AbpDatePickerRange(string label, DateTimeOffset date) + { + Label = label; + AddDate(date); + } + + public AbpDatePickerRange(string label, string start, string end) + { + Label = label; + AddDate(start); + AddDate(end); + } + + public AbpDatePickerRange(string label, string date) + { + Label = label; + AddDate(date); + } public void AddDate(string date) { diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs index 8b64b28d05..9cff72aa23 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/DatePickerOptionsAttribute.cs @@ -1,180 +1,34 @@ using System; -using System.Collections.Generic; +using System.Linq; +using Microsoft.AspNetCore.Mvc.ViewFeatures; namespace Volo.Abp.AspNetCore.Mvc.UI.Bootstrap.TagHelpers.Form.DatePicker; [AttributeUsage(AttributeTargets.Property)] -public class DatePickerOptionsAttribute : Attribute, IAbpDatePickerOptions +public class DatePickerOptionsAttribute : Attribute { - private readonly IAbpDatePickerOptions _abpDatePickerOptionsImplementation; - - public DatePickerOptionsAttribute() + public string DatePickerOptionsPropertyName { get; set; } + + public DatePickerOptionsAttribute(string datePickerOptionsPropertyName) { - _abpDatePickerOptionsImplementation = new AbpDatePickerOptions(); - } - - public string PickerId { - get => _abpDatePickerOptionsImplementation.PickerId; - set => _abpDatePickerOptionsImplementation.PickerId = value; - } - - public DateTime? MinDate { - get => _abpDatePickerOptionsImplementation.MinDate; - set => _abpDatePickerOptionsImplementation.MinDate = value; - } - - public DateTime? MaxDate { - get => _abpDatePickerOptionsImplementation.MaxDate; - set => _abpDatePickerOptionsImplementation.MaxDate = value; - } - - public object MaxSpan { - get => _abpDatePickerOptionsImplementation.MaxSpan; - set => _abpDatePickerOptionsImplementation.MaxSpan = value; - } - - public bool? ShowDropdowns { - get => _abpDatePickerOptionsImplementation.ShowDropdowns; - set => _abpDatePickerOptionsImplementation.ShowDropdowns = value; - } - - public int? MinYear { - get => _abpDatePickerOptionsImplementation.MinYear; - set => _abpDatePickerOptionsImplementation.MinYear = value; - } - - public int? MaxYear { - get => _abpDatePickerOptionsImplementation.MaxYear; - set => _abpDatePickerOptionsImplementation.MaxYear = value; - } - - public AbpDatePickerWeekNumbers WeekNumbers { - get => _abpDatePickerOptionsImplementation.WeekNumbers; - set => _abpDatePickerOptionsImplementation.WeekNumbers = value; + DatePickerOptionsPropertyName = datePickerOptionsPropertyName; } - - public bool? TimePicker { - get => _abpDatePickerOptionsImplementation.TimePicker; - set => _abpDatePickerOptionsImplementation.TimePicker = value; - } - - public int? TimePickerIncrement { - get => _abpDatePickerOptionsImplementation.TimePickerIncrement; - set => _abpDatePickerOptionsImplementation.TimePickerIncrement = value; - } - - public bool? TimePicker24Hour { - get => _abpDatePickerOptionsImplementation.TimePicker24Hour; - set => _abpDatePickerOptionsImplementation.TimePicker24Hour = value; - } - - public bool? TimePickerSeconds { - get => _abpDatePickerOptionsImplementation.TimePickerSeconds; - set => _abpDatePickerOptionsImplementation.TimePickerSeconds = value; - } - - public List Ranges { - get => _abpDatePickerOptionsImplementation.Ranges; - set => _abpDatePickerOptionsImplementation.Ranges = value; - } - - public bool? ShowCustomRangeLabel { - get => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel; - set => _abpDatePickerOptionsImplementation.ShowCustomRangeLabel = value; - } - - public bool? AlwaysShowCalendars { - get => _abpDatePickerOptionsImplementation.AlwaysShowCalendars; - set => _abpDatePickerOptionsImplementation.AlwaysShowCalendars = value; - } - - public AbpDatePickerOpens Opens { - get => _abpDatePickerOptionsImplementation.Opens; - set => _abpDatePickerOptionsImplementation.Opens = value; - } - - public AbpDatePickerDrops Drops { - get => _abpDatePickerOptionsImplementation.Drops; - set => _abpDatePickerOptionsImplementation.Drops = value; - } - - public string ButtonClasses { - get => _abpDatePickerOptionsImplementation.ButtonClasses; - set => _abpDatePickerOptionsImplementation.ButtonClasses = value; - } - - public string TodayButtonClasses { - get => _abpDatePickerOptionsImplementation.TodayButtonClasses; - set => _abpDatePickerOptionsImplementation.TodayButtonClasses = value; - } - - public string ApplyButtonClasses { - get => _abpDatePickerOptionsImplementation.ApplyButtonClasses; - set => _abpDatePickerOptionsImplementation.ApplyButtonClasses = value; - } - - public string ClearButtonClasses { - get => _abpDatePickerOptionsImplementation.ClearButtonClasses; - set => _abpDatePickerOptionsImplementation.ClearButtonClasses = value; - } - - public object Locale { - get => _abpDatePickerOptionsImplementation.Locale; - set => _abpDatePickerOptionsImplementation.Locale = value; - } - - public bool? AutoApply { - get => _abpDatePickerOptionsImplementation.AutoApply; - set => _abpDatePickerOptionsImplementation.AutoApply = value; - } - - public bool? LinkedCalendars { - get => _abpDatePickerOptionsImplementation.LinkedCalendars; - set => _abpDatePickerOptionsImplementation.LinkedCalendars = value; - } - - public bool? AutoUpdateInput { - get => _abpDatePickerOptionsImplementation.AutoUpdateInput; - set => _abpDatePickerOptionsImplementation.AutoUpdateInput = value; - } - - public string ParentEl { - get => _abpDatePickerOptionsImplementation.ParentEl; - set => _abpDatePickerOptionsImplementation.ParentEl = value; - } - - public string DateFormat { - get => _abpDatePickerOptionsImplementation.DateFormat; - set => _abpDatePickerOptionsImplementation.DateFormat = value; - } - - public bool OpenButton { - get => _abpDatePickerOptionsImplementation.OpenButton; - set => _abpDatePickerOptionsImplementation.OpenButton = value; - } - - public bool ClearButton { - get => _abpDatePickerOptionsImplementation.ClearButton; - set => _abpDatePickerOptionsImplementation.ClearButton = value; - } - - public bool SingleOpenAndClearButton { - get => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton; - set => _abpDatePickerOptionsImplementation.SingleOpenAndClearButton = value; - } - - public bool? IsUtc { - get => _abpDatePickerOptionsImplementation.IsUtc; - set => _abpDatePickerOptionsImplementation.IsUtc = value; - } - - public bool? IsIso { - get => _abpDatePickerOptionsImplementation.IsIso; - set => _abpDatePickerOptionsImplementation.IsIso = value; - } - - public object Options { - get => _abpDatePickerOptionsImplementation.Options; - set => _abpDatePickerOptionsImplementation.Options = value; + + public IAbpDatePickerOptions GetDatePickerOptions(ModelExplorer explorer) + { + var properties = explorer.Container.Properties.Where(p => p.Metadata.PropertyName != null && p.Metadata.PropertyName.Equals(DatePickerOptionsPropertyName)).ToList(); + + while (properties.Count == 0) + { + explorer = explorer.Container; + if(explorer.Container == null) + { + return null; + } + + properties = explorer.Container.Properties.Where(p => p.Metadata.PropertyName != null && p.Metadata.PropertyName.Equals(DatePickerOptionsPropertyName)).ToList(); + } + + return properties.FirstOrDefault(p=> p.Model is IAbpDatePickerOptions)?.Model as IAbpDatePickerOptions; } } \ No newline at end of file diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index bbc26e4e1f..c02467e01e 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -290,6 +290,7 @@ $container.data('options', options); abp.dom.initializers.initializeDateRangePickers($container); + $container[0].datePicker = $datePicker[0]; return $container; } }; @@ -355,7 +356,7 @@ } else { end = value[0]; } - options.ranges[key] = [getMoment(start, options), getMoment(end, options.isUtc)]; + options.ranges[key] = [getMoment(start, options), getMoment(end, options)]; }); } @@ -448,7 +449,7 @@ var today = getMoment(undefined, options); $input.data('daterangepicker').setStartDate(today); $input.data('daterangepicker').setEndDate(today); - $input.data('daterangepicker').updateView(); + $input.data('daterangepicker').clickApply(); }); return $todayBtn; From b6247488bc5eb7fbd6dce566bf8d2732ec21a961 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 21 Mar 2023 20:30:01 +0300 Subject: [PATCH 18/28] Add Abp-Date-Picker JavaScript Usage section --- .../AspNetCore/Tag-Helpers/Form-elements.md | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 9140858c11..68dd5e73b1 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -381,4 +381,50 @@ You can set the label of the input in several ways: - You can use the `Label` attribute to set the label directly. This property does not automatically localize the text. To localize the label, use `label="@L["{LocalizationKey}"].Value"`. - You can set it using `[Display(name="{LocalizationKey}")]` attribute ASP.NET Core. -- You can just let **abp** find the localization key for the property. If the `label` or `[DisplayName]` attributes are not set, it tries to find the localization by convention. For example `DisplayName:{YourPropertyName}` or `{YourPropertyName}`. If your property name is FullName, it will search for `DisplayName:FullName` or `{FullName}`. \ No newline at end of file +- You can just let **abp** find the localization key for the property. If the `label` or `[DisplayName]` attributes are not set, it tries to find the localization by convention. For example `DisplayName:{YourPropertyName}` or `{YourPropertyName}`. If your property name is FullName, it will search for `DisplayName:FullName` or `{FullName}`. + +### JavaScript Usage + +````javascript +var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker( + { + label: "New Picker", + } +); +newPicker.insertAfter($('body')); +```` + +````javascript +var newPicker = abp.libs.bootstrapDateRangePicker.createSinglePicker( + { + label: "New Picker", + } +); +newPicker.insertAfter($('body')); +```` + +#### Options + +* `label`: Sets the label of the input. +* `placeholder`: Sets the placeholder of the input. +* `value`: Sets the value of the input. +* `name`: Sets the name of the input. +* `id`: Sets the id of the input. +* `required`: Sets the input as required. +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `size`: Sets the size of the form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. +* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True` +* `is-utc`: Converts the date to UTC when its `True`. The default value is `False`. +* `is-iso`: Converts the date to ISO format when its `True`. The default value is `False`. +* `date-format`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. +* `date-separator`: Sets a character to separate start and end dates. The default value is `-`. +* `startDateName`: Sets the name of the hidden start date input. +* `endDateName`: Sets the name of the hidden end date input. +* `dateName`: Sets the name of the hidden date input. +* Other [datepicker options](https://www.daterangepicker.com/#options). Eg: `start-date: "2020-01-01"`. \ No newline at end of file From b00c8510fbf7fc93628589afcc1ccbc5ec9209e2 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 21 Mar 2023 20:30:01 +0300 Subject: [PATCH 19/28] Add Abp-Date-Picker JavaScript Usage section --- .../AspNetCore/Tag-Helpers/Form-elements.md | 48 ++++++++++++++++++- 1 file changed, 47 insertions(+), 1 deletion(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 9140858c11..f18a955008 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -381,4 +381,50 @@ You can set the label of the input in several ways: - You can use the `Label` attribute to set the label directly. This property does not automatically localize the text. To localize the label, use `label="@L["{LocalizationKey}"].Value"`. - You can set it using `[Display(name="{LocalizationKey}")]` attribute ASP.NET Core. -- You can just let **abp** find the localization key for the property. If the `label` or `[DisplayName]` attributes are not set, it tries to find the localization by convention. For example `DisplayName:{YourPropertyName}` or `{YourPropertyName}`. If your property name is FullName, it will search for `DisplayName:FullName` or `{FullName}`. \ No newline at end of file +- You can just let **abp** find the localization key for the property. If the `label` or `[DisplayName]` attributes are not set, it tries to find the localization by convention. For example `DisplayName:{YourPropertyName}` or `{YourPropertyName}`. If your property name is FullName, it will search for `DisplayName:FullName` or `{FullName}`. + +### JavaScript Usage + +````javascript +var newPicker = abp.libs.bootstrapDateRangePicker.createDateRangePicker( + { + label: "New Picker", + } +); +newPicker.insertAfter($('body')); +```` + +````javascript +var newPicker = abp.libs.bootstrapDateRangePicker.createSinglePicker( + { + label: "New Picker", + } +); +newPicker.insertAfter($('body')); +```` + +#### Options + +* `label`: Sets the label of the input. +* `placeholder`: Sets the placeholder of the input. +* `value`: Sets the value of the input. +* `name`: Sets the name of the input. +* `id`: Sets the id of the input. +* `required`: Sets the input as required. +* `disabled`: Sets the input as disabled. +* `readonly`: Sets the input as read-only. +* `size`: Sets the size of the form-control wrapper element. Available values are + - `AbpFormControlSize.Default` + - `AbpFormControlSize.Small` + - `AbpFormControlSize.Medium` + - `AbpFormControlSize.Large` +* `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. +* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True` +* `is-utc`: Converts the date to UTC when its `True`. The default value is `False`. +* `is-iso`: Converts the date to ISO format when its `True`. The default value is `False`. +* `date-format`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. +* `date-separator`: Sets a character to separate start and end dates. The default value is `-`. +* `startDateName`: Sets the name of the hidden start date input. +* `endDateName`: Sets the name of the hidden end date input. +* `dateName`: Sets the name of the hidden date input. +* Other [datepicker options](https://www.daterangepicker.com/#options). Eg: `startDate: "2020-01-01"`. \ No newline at end of file From 3ad7fb84cfec11152b1341e0d4fe4b2043109ab2 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 21 Mar 2023 20:53:27 +0300 Subject: [PATCH 20/28] Fix javascript createDatepicker options bug --- .../bootstrap/dom-event-handlers.js | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index c02467e01e..0bb5b85782 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -288,8 +288,8 @@ $datePicker.append($hiddenDateElement); } - $container.data('options', options); - abp.dom.initializers.initializeDateRangePickers($container); + $datePicker.data('options', options); + abp.dom.initializers.initializeDateRangePickers($datePicker); $container[0].datePicker = $datePicker[0]; return $container; } From a2ea1a618536c7802d4d11010e48a4ededa6ee61 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 16:57:48 +0300 Subject: [PATCH 21/28] Fix error when adding info option --- .../Form/DatePicker/AbpDatePickerBaseTagHelperService.cs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index dbcd4e23ac..56f509c865 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -101,7 +101,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp new TagHelperAttributeList(new[] { new TagHelperAttribute("class", "input-group") }), (_, _) => Task.FromResult(new DefaultTagHelperContent())); inputGroup.Content.AppendHtml( - TagHelperOutput.Render(Encoder) + openButtonContent + clearButtonContent + infoContent + TagHelperOutput.Render(Encoder) + openButtonContent + clearButtonContent ); var abpDatePickerTag = new TagHelperOutput(TagName, GetBaseTagAttributes(context, output, TagHelper), @@ -110,7 +110,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp abpDatePickerTag.Content.AppendHtml(validationContent); abpDatePickerTag.Content.AppendHtml(GetExtraInputHtml(context, output)); - var innerHtml = labelContent + abpDatePickerTag.Render(Encoder); + var innerHtml = labelContent + abpDatePickerTag.Render(Encoder) + infoContent; var order = GetOrder(); @@ -475,6 +475,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp } var idAttr = inputTag.Attributes.FirstOrDefault(a => a.Name == "id"); + modelExplorer ??= GetModelExpression().ModelExplorer; var localizedText = TagHelperLocalizer.GetLocalizedText(text, modelExplorer); var div = new TagBuilder("div"); From 0fd906d614d6e462dedcb6fbb3bc72a5566c0f69 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 17:17:06 +0300 Subject: [PATCH 22/28] Disable option prevents selection from being made --- .../Form/DatePicker/AbpDatePickerBaseTagHelperService.cs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index 56f509c865..2a373b0cf9 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -589,6 +589,8 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp abpButtonTagHelper.ButtonType = AbpButtonType.Outline_Secondary; abpButtonTagHelper.Icon = icon; + abpButtonTagHelper.Disabled = TagHelper.IsDisabled; + if (!visible) { attributes.AddClass("d-none"); From 8d109784d72fdf4a2cc0d9f845389a9b05059aac Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 17:47:02 +0300 Subject: [PATCH 23/28] Update required symbol rule --- .../TagHelpers/Form/AbpInputTagHelperService.cs | 4 +++- .../TagHelpers/Form/AbpSelectTagHelperService.cs | 4 +++- .../Form/DatePicker/AbpDatePickerBaseTagHelperService.cs | 4 +++- 3 files changed, 9 insertions(+), 3 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs index 0a3d1e1c08..a3cecfa471 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpInputTagHelperService.cs @@ -294,8 +294,10 @@ public class AbpInputTagHelperService : AbpTagHelperService { return ""; } + + var isHaveRequiredAttribute = context.AllAttributes.Any(a => a.Name == "required"); - return TagHelper.AspFor.ModelExplorer.GetAttribute() != null ? " * " : ""; + return TagHelper.AspFor.ModelExplorer.GetAttribute() != null || isHaveRequiredAttribute ? " * " : ""; } protected virtual string GetInfoAsHtml(TagHelperContext context, TagHelperOutput output, TagHelperOutput inputTag, bool isCheckbox) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs index 78ef04d1d5..eefb6606ef 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/AbpSelectTagHelperService.cs @@ -196,8 +196,10 @@ public class AbpSelectTagHelperService : AbpTagHelperService { return ""; } + + var isHaveRequiredAttribute = context.AllAttributes.Any(a => a.Name == "required"); - return TagHelper.AspFor.ModelExplorer.GetAttribute() != null ? " * " : ""; + return TagHelper.AspFor.ModelExplorer.GetAttribute() != null || isHaveRequiredAttribute ? " * " : ""; } protected virtual void AddInfoTextId(TagHelperOutput inputTagHelperOutput) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index 2a373b0cf9..e5fc38ce04 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -535,8 +535,10 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp { return ""; } + + var isHaveRequiredAttribute = context.AllAttributes.Any(a => a.Name == "required"); - return GetAttribute() != null ? " * " : ""; + return GetAttribute() != null || isHaveRequiredAttribute ? " * " : ""; } protected abstract ModelExpression GetModelExpression(); From d1fe97342f3b2f8089c8688aaee0a0e0582ae3bb Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 18:15:38 +0300 Subject: [PATCH 24/28] Align clean and apply buttons today --- .../bootstrap/dom-event-handlers.js | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 5418e623e5..8c97539e66 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -483,12 +483,8 @@ function addExtraButtons(options, $dateRangePicker, $input) { var extraButtons = [getTodayButton(options, $input), getClearButton(options, $input, $dateRangePicker)]; - if ($dateRangePicker.container.find('.drp-buttons').css('display') !== 'none') { - - $.each(extraButtons, function (index, value) { - $dateRangePicker.container.find('.drp-buttons').prepend(value); - }); - } else { + + if ($dateRangePicker.container.hasClass('auto-apply')) { var $div = $('
'); $div.css('display', 'block'); $.each(extraButtons, function (index, value) { @@ -496,6 +492,10 @@ }); $div.insertAfter($dateRangePicker.container.find('.drp-buttons')); + } else { + $.each(extraButtons, function (index, value) { + $dateRangePicker.container.find('.drp-buttons').prepend(value); + }); } } From 0c8faae3bd29d60529794c631c162a1f58181ab7 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 18:26:27 +0300 Subject: [PATCH 25/28] fix week numbers iso option --- .../Form/DatePicker/AbpDatePickerBaseTagHelperService.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs index e5fc38ce04..82273097cf 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Bootstrap/TagHelpers/Form/DatePicker/AbpDatePickerBaseTagHelperService.cs @@ -264,7 +264,7 @@ public abstract class AbpDatePickerBaseTagHelperService : AbpTagHelp attrList.Add("data-show-week-numbers", "true"); break; case AbpDatePickerWeekNumbers.Iso: - attrList.Add("data-show-iso-week-numbers", "true"); + attrList.Add("data-show-i-s-o-week-numbers", "true"); break; } From ef1774ed02a2066612429a3282ea56dc41feed1d Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 18:40:15 +0300 Subject: [PATCH 26/28] Update form elements documents --- .../UI/AspNetCore/Tag-Helpers/Form-elements.md | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 64377f75cd..766bea2306 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -359,7 +359,8 @@ You can set some of the attributes on your c# property, or directly on HTML tag. * `label`: Sets the label of input. * `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. * `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. -* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True` +* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True`. +* `single-open-and-clear-button`: Shows the open and clear buttons in a single button when it's `True`. The default value is `True`. * `is-utc`: Converts the date to UTC when its `True`. The default value is `False`. * `is-iso`: Converts the date to ISO format when its `True`. The default value is `False`. * `date-format`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. @@ -418,12 +419,13 @@ newPicker.insertAfter($('body')); - `AbpFormControlSize.Small` - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` -* `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. -* `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True` -* `is-utc`: Converts the date to UTC when its `True`. The default value is `False`. -* `is-iso`: Converts the date to ISO format when its `True`. The default value is `False`. -* `date-format`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. -* `date-separator`: Sets a character to separate start and end dates. The default value is `-`. +* `openButton`: A button to open the datepicker will be added when its `True`. The default value is `True`. +* `clearButton`: A button to clear the datepicker will be added when its `True`. The default value is `True`. +* `singleOpenAndClearButton`: Shows the open and clear buttons in a single button when it's `True`. The default value is `True`. +* `isUtc`: Converts the date to UTC when its `True`. The default value is `False`. +* `isIso`: Converts the date to ISO format when its `True`. The default value is `False`. +* `dateFormat`: Sets the date format of the input. The default format is the user's culture date format. You need to provide a JavaScript date format convention. Eg: `YYYY-MM-DDTHH:MM:SSZ`. +* `dateSeparator`: Sets a character to separate start and end dates. The default value is `-`. * `startDateName`: Sets the name of the hidden start date input. * `endDateName`: Sets the name of the hidden end date input. * `dateName`: Sets the name of the hidden date input. From 2c52ba830abafbf431e4305d6f28d26104599800 Mon Sep 17 00:00:00 2001 From: Salih Date: Tue, 28 Mar 2023 18:40:36 +0300 Subject: [PATCH 27/28] Added missing feature --- .../bootstrap/dom-event-handlers.js | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js index 8c97539e66..945df5d0c6 100644 --- a/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js +++ b/framework/src/Volo.Abp.AspNetCore.Mvc.UI.Theme.Shared/wwwroot/libs/abp/aspnetcore-mvc-ui-theme-shared/bootstrap/dom-event-handlers.js @@ -247,6 +247,10 @@ if (options.readonly) { $dateInput.attr('readonly', true) } + + if(options.placeholder) { + $dateInput.attr('placeholder', options.placeholder) + } if (options.size) { switch (options.size) { @@ -269,11 +273,17 @@ if (options.openButton !== false) { var $openButton = $(''); $inputGroup.append($openButton); + if(options.disabled) { + $openButton.attr('disabled', 'disabled') + } } if (options.clearButton !== false) { var $clearButton = $(''); $inputGroup.append($clearButton); + if(options.disabled) { + $clearButton.attr('disabled', 'disabled') + } } $datePicker.append($inputGroup); From 639cbdf59b541db27dab1faaa96662b7b9fa8a1b Mon Sep 17 00:00:00 2001 From: Salih Date: Wed, 29 Mar 2023 14:17:14 +0300 Subject: [PATCH 28/28] Update Form-elements.md --- docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md index 766bea2306..54e9712d30 100644 --- a/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md +++ b/docs/en/UI/AspNetCore/Tag-Helpers/Form-elements.md @@ -86,7 +86,7 @@ You can set some of the attributes on your c# property, or directly on HTML tag. * `disabled`: Sets the input as disabled. * `readonly`: Sets the input as read-only. * `label`: Sets the label of input. -* `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. +* `required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. `asp-format`, `name` and `value` attributes of [Asp.Net Core Input Tag Helper](https://docs.microsoft.com/en-us/aspnet/core/mvc/views/working-with-forms?view=aspnetcore-7.0#the-input-tag-helper) are also valid for `abp-input` tag helper. @@ -193,7 +193,7 @@ You can set some of the attributes on your c# property, or directly on HTML tag. - `AbpFormControlSize.Medium` - `AbpFormControlSize.Large` - `label`: Sets the label of input. -- `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. +- `required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. ### Label & Localization @@ -357,7 +357,7 @@ You can set some of the attributes on your c# property, or directly on HTML tag. * `disabled`: Sets the input as disabled. * `readonly`: Sets the input as read-only. * `label`: Sets the label of input. -* `display-required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. +* `required-symbol`: Adds the required symbol `(*)` to the label when the input is required. The default value is `True`. * `open-button`: A button to open the datepicker will be added when its `True`. The default value is `True`. * `clear-button`: A button to clear the datepicker will be added when its `True`. The default value is `True`. * `single-open-and-clear-button`: Shows the open and clear buttons in a single button when it's `True`. The default value is `True`.