From e204c4e13ad639727aa16f91df7bf3e74c0608bb Mon Sep 17 00:00:00 2001 From: Salih Date: Sun, 19 Feb 2023 18:12:36 +0300 Subject: [PATCH] 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