| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486 |
- using FluentValidation.Internal;
- using GreenTree.Strohrmann.ERP.Core.Extension;
- using Microsoft.AspNetCore.Html;
- using Microsoft.AspNetCore.Mvc.ModelBinding;
- using Microsoft.AspNetCore.Mvc.Rendering;
- using Microsoft.EntityFrameworkCore.Infrastructure;
- using Newtonsoft.Json;
- using Newtonsoft.Json.Linq;
- using System;
- using System.Collections.Generic;
- using System.Globalization;
- using System.IO;
- using System.Linq;
- using System.Linq.Expressions;
- using System.Reflection;
- using System.Text;
- using System.Threading.Tasks;
- namespace GreenTree.Strohrmann.ERP.Web.Extension
- {
- public static class HtmlContentExtension
- {
- #region Inputs
- /// <summary>
- /// Return HTML markup for the <paramref name="expression"/>, using a display template for a bootstrap extension token field.
- /// See <see href="https://sliptree.github.io/bootstrap-tokenfield/">bootstrap-tokenfield</see> for more information of the
- /// input type.
- /// </summary>
- /// <typeparam name="TModel">Model type.</typeparam>
- /// <typeparam name="TValue">Model value type.</typeparam>
- /// <param name="htmlHelper">HtmlHelper context.</param>
- /// <param name="expression">Expression for the requested model enumeration value.</param>
- /// <param name="delimiter">The delimiter string used to seperate token values.</param>
- /// <param name="htmlAttributes">Additional HTML attributes.</param>
- /// <param name="availableValues">The available values for the tokenbox.</param>
- /// <param name="allowOnlyOnce"><c>True</c> when every available value can only be selected once.</param>
- public static IHtmlContent TokenBoxFor<TModel, TValue>(
- this IHtmlHelper<TModel> htmlHelper,
- Expression<Func<TModel, TValue>> expression,
- string delimiter = "|",
- object htmlAttributes = null,
- string[] availableValues = null,
- bool allowOnlyOnce = true) where TValue : IEnumerable<string>
- {
- var attributes = htmlAttributes == null
- ? new string[0]
- : htmlAttributes.GetType().GetProperties()
- .Select(p => String.Format("{0}='{1}'", p.Name.Replace("_", "-"), p.GetValue(htmlAttributes)))
- .ToArray();
- var func = expression.Compile();
- var id = Guid.NewGuid().ToShortString();
- var scriptBuilder = new StringBuilder();
- var memberInfo = expression.Body.NodeType == ExpressionType.MemberAccess
- ? ((MemberExpression)expression.Body).Member
- : null;
- var type = expression.Body.GetType();
- if (availableValues != null)
- {
- var autoComplete = JsonConvertWithoutQuotes(new
- {
- autocomplete = new
- {
- source = availableValues,
- delay = 200
- },
- showAutocompleteOnFocus = true
- });
- scriptBuilder.AppendFormat(
- "<script>" +
- " $('#{0}').tokenfield({1})",
- id, autoComplete);
- if (allowOnlyOnce)
- {
- scriptBuilder.Append(
- ".on('tokenfield:createtoken', function (e) { " +
- " if ($(this).tokenfield('getTokens').some(t => t.value === e.attrs.value)) return false;" +
- "})");
- }
- if (memberInfo != null)
- {
- var inputCreationScriptPart = String.Format(
- "function (e) {{ " +
- " $(\"[name = '{1}'\").remove();" +
- " $(this).tokenfield('getTokens').forEach(" +
- " function (obj) {{ $('#{0}').after('<input type=\"hidden\" name=\"{1}\" value=\"' + obj.value + '\" />'); }});" +
- "}}", id, memberInfo.Name);
- scriptBuilder.AppendFormat(
- ".on('tokenfield:createdtoken', {0})", inputCreationScriptPart);
- scriptBuilder.AppendFormat(
- ".on('tokenfield:removedtoken', {0})", inputCreationScriptPart);
- }
- scriptBuilder.Append(";</script>");
- }
- else
- {
- scriptBuilder.AppendFormat("<script>$('#{0}').tokenfield();</script>", id);
- }
- if (htmlHelper.ViewData.Model == null)
- {
- return new HtmlString(
- String.Format(
- "<input id='{0}' class='tokenBox' value='{1}' data-delimiter='{2}' {3} /> {4}",
- id,
- String.Empty,
- delimiter,
- String.Join(" ", attributes),
- scriptBuilder));
- }
- else
- {
- var values = func(htmlHelper.ViewData.Model);
- var valueInputs = values
- .Select(v => String.Format(
- "<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
- memberInfo == null
- ? id
- : memberInfo.Name,
- v));
- return new HtmlString(
- String.Format(
- "<input id='{0}' class='tokenBox' value='{1}' data-delimiter='{2}' {3} /> {4} {5}",
- id,
- values == null
- ? String.Empty
- : String.Join(delimiter, values),
- delimiter,
- String.Join(" ", attributes),
- scriptBuilder,
- String.Join(" ", valueInputs)));
- }
- }
- /// <summary>
- /// Return HTML markup for the <paramref name="expression"/>, using a bootstrap badge containing 'Yes' or 'No'.
- /// See <see href="https://getbootstrap.com/docs/4.1/components/badge/">bootstrap badge</see> for more information of the badge.
- /// </summary>
- /// <typeparam name="TModel">Model type.</typeparam>
- /// <param name="htmlHelper">HtmlHelper context.</param>
- /// <param name="expression">Expression for the requested model bool value.</param>
- public static IHtmlContent YesNoBadgeFor<TModel>(
- this IHtmlHelper<TModel> htmlHelper,
- Expression<Func<TModel, bool>> expression)
- {
- var func = expression.Compile();
- if (htmlHelper.ViewData.Model == null)
- {
- return new HtmlString("<span class='badge badge-secondary'>N/A</span>");
- }
- else
- {
- return
- func(htmlHelper.ViewData.Model)
- ? new HtmlString("<span class='badge badge-success'>Ja</span>")
- : new HtmlString("<span class='badge badge-danger'>Nein</span>");
- }
- }
- /// <summary>
- /// Return HTML markup for the <paramref name="expression"/>, using a display template for a country selection field.
- /// </summary>
- /// <typeparam name="TModel">Model type.</typeparam>
- /// <typeparam name="TValue">Model value type.</typeparam>
- /// <param name="htmlHelper">HtmlHelper context.</param>
- /// <param name="expression">Expression for the requested model enumeration value.</param>
- /// <param name="htmlAttributes">Additional HTML attributes.</param>
- public static IHtmlContent CountrySelectionFor<TModel, TValue>(
- this IHtmlHelper<TModel> htmlHelper,
- Expression<Func<TModel, TValue>> expression,
- object htmlAttributes = null)
- {
- var attributes = htmlAttributes == null
- ? new string[0]
- : htmlAttributes.GetType().GetProperties()
- .Select(p => String.Format("{0}='{1}'", p.Name.Replace("_", "-"), p.GetValue(htmlAttributes)))
- .ToArray();
- var func = expression.Compile();
- var funcVal = htmlHelper.ViewData.Model == null
- ? String.Empty
- : func(htmlHelper.ViewData.Model).ToString();
- var memberInfo = expression.Body.NodeType == ExpressionType.MemberAccess
- ? ((MemberExpression)expression.Body).Member
- : null;
- var name = memberInfo == null
- ? Guid.NewGuid().ToShortString()
- : memberInfo.Name;
- var selectBuilder = new StringBuilder();
- selectBuilder.AppendFormat("<select id=\"{0}\" name =\"{0}\" {1}>", name, String.Join(" ", htmlAttributes));
- var countries = CultureInfo.GetCultures(CultureTypes.AllCultures)
- .Where(c => c.LCID != CultureInfo.InvariantCulture.LCID && !c.IsNeutralCulture)
- .Select(c => new RegionInfo(c.LCID))
- .Distinct()
- .OrderBy(r => r.DisplayName);
- foreach (var country in countries)
- {
- if (country.EnglishName == funcVal)
- selectBuilder.AppendFormat("<option selected value=\"{0}\">{1}</option>", country.EnglishName, country.DisplayName);
- else
- selectBuilder.AppendFormat("<option value=\"{0}\">{1}</option>", country.EnglishName, country.DisplayName);
- }
- selectBuilder.Append("</select>");
- return new HtmlString(selectBuilder.ToString());
- }
- /// <summary>
- /// Generates a Span HTML element
- /// </summary>
- /// <param name="htmlHelper">HtmlHelper context.</param>
- /// <param name="content">The span content text.</param>
- /// <param name="htmlAttributes">Additional HTML attributes.</param>
- /// <returns></returns>
- public static IHtmlContent Span(this IHtmlHelper htmlHelper, string content, object htmlAttributes = null)
- {
- var attributes = htmlAttributes == null
- ? new string[0]
- : htmlAttributes.GetType().GetProperties()
- .Select(p => String.Format("{0}='{1}'", p.Name.Replace("_", "-"), p.GetValue(htmlAttributes)))
- .ToArray();
- var htmlString = String.Format("<span {0}>{1}</span>", String.Join(" ", attributes), content);
- return new HtmlString(htmlString);
- }
- /// <summary>
- /// Return HTML markup for the <paramref name="valueExpression"/>, using a display template for a search selection field.
- /// </summary>
- /// <typeparam name="TModel">Model type.</typeparam>
- /// <typeparam name="TValue">Model value type.</typeparam>
- /// <param name="htmlHelper">HtmlHelper context.</param>
- /// <param name="valueExpression">Expression for the requested model value.</param>
- /// <param name="textExpression">Expression for the requested model text.</param>
- /// <param name="searchActionUrl">POST action URL that returns a model enumeration as JSON result.</param>
- /// <param name="htmlAttributesValue">Additional HTML attributes for the value input.</param>
- /// <param name="htmlAttributesText">Additional HTML attributes for the text input.</param>
- /// <returns></returns>
- public static IHtmlContent SearchFor<TModel, TValue>(
- this IHtmlHelper<TModel> htmlHelper,
- Expression<Func<TModel, TValue>> valueExpression,
- Expression<Func<TModel, string>> textExpression,
- string searchActionUrl,
- object htmlAttributesValue = null,
- object htmlAttributesText = null)
- {
- var attributesText = htmlAttributesText == null
- ? new string[0]
- : htmlAttributesText.GetType().GetProperties()
- .Where(p => p.Name != "name")
- .Select(p => String.Format("{0}='{1}'", p.Name.Replace("_", "-"), p.GetValue(htmlAttributesText)))
- .ToArray();
- var attributesValue = htmlAttributesValue == null
- ? new string[0]
- : htmlAttributesValue.GetType().GetProperties()
- .Where(p => p.Name != "name")
- .Select(p => String.Format("{0}='{1}'", p.Name.Replace("_", "-"), p.GetValue(htmlAttributesValue)))
- .ToArray();
- var id = RandomId();
- var valFunc = valueExpression.Compile();
- var funcVal = htmlHelper.ViewData.Model == null
- ? default
- : valFunc(htmlHelper.ViewData.Model);
- var isDefaultValue = funcVal == null || (funcVal != null && funcVal.ToString() == default(TValue).ToString());
- var textFunc = textExpression.Compile();
- var funcText = htmlHelper.ViewData.Model == null
- ? default
- : textFunc(htmlHelper.ViewData.Model);
- var memberInfoText = textExpression.Body.NodeType == ExpressionType.MemberAccess
- ? ((MemberExpression)textExpression.Body).Member
- : null;
- var nameText = memberInfoText == null
- ? Guid.NewGuid().ToShortString()
- : memberInfoText.Name;
- if (htmlAttributesText != null && htmlAttributesText.GetType().GetProperty("name") != null)
- nameText = htmlAttributesText.GetType().GetProperty("name").GetValue(htmlAttributesText).ToString();
- var memberInfoValue = valueExpression.Body.NodeType == ExpressionType.MemberAccess
- ? ((MemberExpression)valueExpression.Body).Member
- : null;
- var nameValue = memberInfoValue == null
- ? Guid.NewGuid().ToShortString()
- : memberInfoValue.Name;
- if (htmlAttributesValue != null && htmlAttributesValue.GetType().GetProperty("name") != null)
- nameValue = htmlAttributesValue.GetType().GetProperty("name").GetValue(htmlAttributesValue).ToString();
- var scriptBuilder = new StringBuilder();
- scriptBuilder.AppendFormat(
- "<script type='text/javascript'>\n" +
- "$(document).ready(function() {{\n" +
- " $(\"#text_{0}\").on('keypress', function (e) {{\n" +
- " if (e.keyCode == 13)\n" +
- " {{\n" +
- " search_{0}();\n" +
- " e.preventDefault();\n" +
- " }};\n" +
- " }});\n" +
- " $(\"#text_{0}\").on('keydown', function (e) {{\n" +
- " if (e.keyCode == 8 && $(\"#value_{0}\").val() != '') {{\n" +
- " $(\"#text_{0}\").val('');\n" +
- " $(\"#value_{0}\").val('');\n" +
- " $(\"#text_{0}\").next().children('.fa-check-circle').fadeOut('fast', function() {{\n" +
- " $(\"#text_{0}\").next().children(\".fa-ellipsis-h\").fadeIn('fast');\n" +
- " }});\n" +
- " e.preventDefault();\n" +
- " }};\n" +
- " }});\n" +
- "}});\n" +
- "\n" +
- "function search_{0}()\n" +
- "{{\n" +
- " $.ajax({{\n" +
- " method: 'POST',\n" +
- " url: '{1}',\n" +
- " data:\n" +
- " {{\n" +
- " SearchTerm: $('#text_{0}').val()\n" +
- " }},\n" +
- " success: function(data) {{\n" +
- " $(\"#searchModal_{0}\").find('.list-group').empty();\n" +
- " if (data.length > 0)\n" +
- " {{\n" +
- " $(data).each(function(index, elem) {{\n" +
- " $(\"#searchModal_{0}\").find('.list-group').append(\n" +
- " \"<a href='#' class='list-group-item list-group-item-info list-group-item-action'" +
- " data-toggle='list' data-val='{{0}}' data-text='{{1}}' ondblclick='select_{0}()'>{{1}}</a>\"\n" +
- " .format(elem.searchId, elem.searchText));\n" +
- " }});\n" +
- " }}\n" +
- " else\n" +
- " {{\n" +
- " $(\"#searchModal_{0}\").find('.list-group').append(\n" +
- " \"'<button type='button' class='list-group-item'>Keine Treffer</button>'\");\n" +
- " }}\n" +
- " $(\"#searchModal_{0}\").modal('show');\n" +
- " }},\n" +
- " error: function(msg) {{\n" +
- " \n" +
- " }}\n" +
- " }});\n" +
- "}}\n" +
- "\n" +
- "function select_{0}()\n" +
- "{{\n" +
- " $(\"#searchModal_{0}\").modal('hide');\n" +
- " var val = $(\"#searchModal_{0}\").find('a.active').attr('data-val');\n" +
- " var text = $(\"#searchModal_{0}\").find('a.active').attr('data-text');\n" +
- " $(\"#value_{0}\").val(val);\n" +
- " $(\"#text_{0}\").val(text);\n" +
- " $(\"#text_{0}\").next().children('.fa-ellipsis-h').fadeOut('fast', function() {{\n" +
- " $(\"#text_{0}\").next().children('.fa-check-circle').fadeIn('fast');\n" +
- " $(\"#text_{0}\").focus();\n" +
- " }});\n" +
- "}}" +
- "</script>",
- id,
- searchActionUrl
- );
- var contentBuilder = new StringBuilder();
- contentBuilder.AppendFormat(
- "<div class='input-group'>\n" +
- "<div class='input-group-prepend'>\n" +
- "<button class='btn btn-info fas fa-search' type='button' onclick='search_{0}()'></button>\n" +
- "</div>\n" +
- "<input id='text_{0}' type='text' name='{1}' value='{2}' class='form-control' placeholder='Suchbegriff'\n" +
- " aria-label='Suchbegriff' aria-describedby='basic-addon1' {5} />\n" +
- "<div class='input-group-append'>\n" +
- " <span class='input-group-text bg-success text-white rounded-right fas fa-cust-lh fa-check-circle' {7}></span>\n" +
- " <span class='input-group-text rounded-right fas fa-cust-lh fa-ellipsis-h' {8}></span>\n" +
- "</div>\n" +
- "</div>\n" +
- "\n" +
- "<input id='value_{0}' type='hidden' name='{3}' value='{4}' {6} />\n" +
- "\n" +
- "<div id='searchModal_{0}' class='modal fade'>\n" +
- "<div class='modal-dialog'>\n" +
- "<div class='modal-content'>\n" +
- "<div class='modal-header'>\n" +
- "<h4 class='modal-title'>Suchergebnisse</h4>\n" +
- "</div>\n" +
- "<div class='modal-body overflow-auto' style='max-height: 400px'>\n" +
- "<div class='list-group'>\n" +
- "</div>\n" +
- "</div>\n" +
- "<div class='modal-footer'>\n" +
- "<div class='btn btn-secondary' data-dismiss='modal'>Schließen</div>\n" +
- "<div class='btn btn-success' onclick='select_{0}()'>Auswählen</div>\n" +
- "</div>\n" +
- "</div>\n" +
- "</div>\n" +
- "</div>",
- id,
- nameText,
- funcText,
- nameValue,
- funcVal,
- String.Join(" ", attributesText),
- String.Join(" ", attributesValue),
- (htmlHelper.ViewData.Model == null || isDefaultValue ? "style='display: none'" : String.Empty),
- (htmlHelper.ViewData.Model == null || isDefaultValue ? String.Empty : "style='display: none'")
- );
- var htmlString = String.Format("{0}\n{1}", scriptBuilder.ToString(), contentBuilder.ToString());
- return new HtmlString(htmlString);
- }
- #endregion
- #region Helper
- /// <summary>
- /// Generates a random short ID string
- /// </summary>
- /// <param name="htmlHelper">HtmlHelper context.</param>
- public static string RandomId(this IHtmlHelper htmlHelper)
- {
- return Guid.NewGuid().ToShortString();
- }
- /// <summary>
- /// Generates a random short ID string
- /// </summary>
- public static string RandomId()
- {
- return Guid.NewGuid().ToShortString();
- }
- /// <summary>
- /// Converts an object in a JS literal object format
- /// </summary>
- /// <param name="value">The object to be converted.</param>
- private static string JsonConvertWithoutQuotes(object value)
- {
- var serializer = new JsonSerializer();
- var stringWriter = new StringWriter();
- using (var writer = new JsonTextWriter(stringWriter))
- {
- writer.QuoteName = false;
- serializer.Serialize(writer, value);
- }
- return stringWriter.ToString();
- }
- #endregion
- }
- }
|