HtmlContentExtension.cs 7.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198
  1. using FluentValidation.Internal;
  2. using GreenTree.Strohrmann.ERP.Core.Extension;
  3. using Microsoft.AspNetCore.Html;
  4. using Microsoft.AspNetCore.Mvc.ModelBinding;
  5. using Microsoft.AspNetCore.Mvc.Rendering;
  6. using Microsoft.EntityFrameworkCore.Infrastructure;
  7. using Newtonsoft.Json;
  8. using Newtonsoft.Json.Linq;
  9. using System;
  10. using System.Collections.Generic;
  11. using System.IO;
  12. using System.Linq;
  13. using System.Linq.Expressions;
  14. using System.Text;
  15. using System.Threading.Tasks;
  16. namespace GreenTree.Strohrmann.ERP.Web.Extension
  17. {
  18. public static class HtmlContentExtension
  19. {
  20. #region Inputs
  21. /// <summary>
  22. /// Return HTML markup for the <paramref name="expression"/>, using a display template for a bootstrap extension token field.
  23. /// See <see href="https://sliptree.github.io/bootstrap-tokenfield/">bootstrap-tokenfield</see> for more information of the
  24. /// input type.
  25. /// </summary>
  26. /// <typeparam name="TModel">Model type.</typeparam>
  27. /// <typeparam name="TValue">Model value type.</typeparam>
  28. /// <param name="htmlHelper">HtmlHelper context.</param>
  29. /// <param name="expression">Expression for the requested model enumeration value.</param>
  30. /// <param name="delimiter">The delimiter string used to seperate token values.</param>
  31. /// <param name="htmlAttributes">Additional HTML attributes.</param>
  32. /// <param name="availableValues">The available values for the tokenbox.</param>
  33. /// <param name="allowOnlyOnce"><c>True</c> when every available value can only be selected once.</param>
  34. public static IHtmlContent TokenBoxFor<TModel, TValue>(
  35. this IHtmlHelper<TModel> htmlHelper,
  36. Expression<Func<TModel, TValue>> expression,
  37. string delimiter = "|",
  38. object htmlAttributes = null,
  39. string[] availableValues = null,
  40. bool allowOnlyOnce = true) where TValue : IEnumerable<string>
  41. {
  42. var attributes = htmlAttributes == null
  43. ? new string[0]
  44. : htmlAttributes.GetType().GetProperties()
  45. .Select(p => String.Format("{0}='{1}'", p.Name.Replace("_", "-"), p.GetValue(htmlAttributes)))
  46. .ToArray();
  47. var func = expression.Compile();
  48. var id = Guid.NewGuid().ToShortString();
  49. var scriptBuilder = new StringBuilder();
  50. var memberInfo = expression.Body.NodeType == ExpressionType.MemberAccess
  51. ? ((MemberExpression)expression.Body).Member
  52. : null;
  53. var type = expression.Body.GetType();
  54. if (availableValues != null)
  55. {
  56. var autoComplete = JsonConvertWithoutQuotes(new
  57. {
  58. autocomplete = new
  59. {
  60. source = availableValues,
  61. delay = 200
  62. },
  63. showAutocompleteOnFocus = true
  64. });
  65. scriptBuilder.AppendFormat(
  66. "<script>" +
  67. " $('#{0}').tokenfield({1})",
  68. id, autoComplete);
  69. if (allowOnlyOnce)
  70. {
  71. scriptBuilder.Append(
  72. ".on('tokenfield:createtoken', function (e) { " +
  73. " if ($(this).tokenfield('getTokens').some(t => t.value === e.attrs.value)) return false;" +
  74. "})");
  75. }
  76. if (memberInfo != null)
  77. {
  78. var inputCreationScriptPart = String.Format(
  79. "function (e) {{ " +
  80. " $(\"[name = '{1}'\").remove();" +
  81. " $(this).tokenfield('getTokens').forEach(" +
  82. " function (obj) {{ $('#{0}').after('<input type=\"hidden\" name=\"{1}\" value=\"' + obj.value + '\" />'); }});" +
  83. "}}", id, memberInfo.Name);
  84. scriptBuilder.AppendFormat(
  85. ".on('tokenfield:createdtoken', {0})", inputCreationScriptPart);
  86. scriptBuilder.AppendFormat(
  87. ".on('tokenfield:removedtoken', {0})", inputCreationScriptPart);
  88. }
  89. scriptBuilder.Append(";</script>");
  90. }
  91. else
  92. {
  93. scriptBuilder.AppendFormat("<script>$('#{0}').tokenfield();</script>", id);
  94. }
  95. if (htmlHelper.ViewData.Model == null)
  96. {
  97. return new HtmlString(
  98. String.Format(
  99. "<input id='{0}' class='tokenBox' value='{1}' data-delimiter='{2}' {3} /> {4}",
  100. id,
  101. String.Empty,
  102. delimiter,
  103. String.Join(" ", attributes),
  104. scriptBuilder));
  105. }
  106. else
  107. {
  108. var values = func(htmlHelper.ViewData.Model);
  109. var valueInputs = values
  110. .Select(v => String.Format(
  111. "<input type=\"hidden\" name=\"{0}\" value=\"{1}\" />",
  112. memberInfo == null
  113. ? id
  114. : memberInfo.Name,
  115. v));
  116. return new HtmlString(
  117. String.Format(
  118. "<input id='{0}' class='tokenBox' value='{1}' data-delimiter='{2}' {3} /> {4} {5}",
  119. id,
  120. values == null
  121. ? String.Empty
  122. : String.Join(delimiter, values),
  123. delimiter,
  124. String.Join(" ", attributes),
  125. scriptBuilder,
  126. String.Join(" ", valueInputs)));
  127. }
  128. }
  129. /// <summary>
  130. /// Return HTML markup for the <paramref name="expression"/>, using a bootstrap badge containing 'Yes' or 'No'.
  131. /// See <see href="https://getbootstrap.com/docs/4.1/components/badge/">bootstrap badge</see> for more information of the badge.
  132. /// </summary>
  133. /// <typeparam name="TModel">Model type.</typeparam>
  134. /// <param name="htmlHelper">HtmlHelper context.</param>
  135. /// <param name="expression">Expression for the requested model bool value.</param>
  136. public static IHtmlContent YesNoBadgeFor<TModel>(
  137. this IHtmlHelper<TModel> htmlHelper,
  138. Expression<Func<TModel, bool>> expression)
  139. {
  140. var func = expression.Compile();
  141. if (htmlHelper.ViewData.Model == null)
  142. {
  143. return new HtmlString("<span class='badge badge-secondary'>N/A</span>");
  144. }
  145. else
  146. {
  147. return
  148. func(htmlHelper.ViewData.Model)
  149. ? new HtmlString("<span class='badge badge-success'>Ja</span>")
  150. : new HtmlString("<span class='badge badge-danger'>Nein</span>");
  151. }
  152. }
  153. #endregion
  154. #region Helper
  155. /// <summary>
  156. /// Converts an object in a JS literal object format
  157. /// </summary>
  158. /// <param name="value">The object to be converted.</param>
  159. private static string JsonConvertWithoutQuotes(object value)
  160. {
  161. var serializer = new JsonSerializer();
  162. var stringWriter = new StringWriter();
  163. using (var writer = new JsonTextWriter(stringWriter))
  164. {
  165. writer.QuoteName = false;
  166. serializer.Serialize(writer, value);
  167. }
  168. return stringWriter.ToString();
  169. }
  170. #endregion
  171. }
  172. }