From 112a5ddc508c7b21326d12050d6b063f35146872 Mon Sep 17 00:00:00 2001 From: sornaks Date: Tue, 22 Apr 2014 14:18:59 -0700 Subject: [PATCH] Changes enabling TextArea, TextAreaFor. Changing the interface to directly include Rows and Columns. --- samples/MvcSample.Web/HomeController.cs | 1 + samples/MvcSample.Web/Models/User.cs | 2 +- .../MvcSample.Web/Views/Home/Create.cshtml | 8 ++ .../Properties/Resources.Designer.cs | 16 ++++ .../Rendering/Html/HtmlHelper.cs | 75 +++++++++++++------ .../Rendering/Html/HtmlHelperOfT.cs | 8 ++ .../Rendering/HtmlHelperInputExtensions.cs | 48 ++++++++++++ .../Rendering/IHtmlHelper.cs | 18 +++++ .../Rendering/IHtmlHelperOfT.cs | 13 ++++ src/Microsoft.AspNet.Mvc.Core/Resources.resx | 5 +- 10 files changed, 169 insertions(+), 25 deletions(-) diff --git a/samples/MvcSample.Web/HomeController.cs b/samples/MvcSample.Web/HomeController.cs index 4ecaecd733..ba95f76de5 100644 --- a/samples/MvcSample.Web/HomeController.cs +++ b/samples/MvcSample.Web/HomeController.cs @@ -96,6 +96,7 @@ namespace MvcSample.Web Address = "Dependents address", Alive = false, }, + About = "I am a Software Engineer" }; return user; diff --git a/samples/MvcSample.Web/Models/User.cs b/samples/MvcSample.Web/Models/User.cs index a92366ede6..97189a7af1 100644 --- a/samples/MvcSample.Web/Models/User.cs +++ b/samples/MvcSample.Web/Models/User.cs @@ -13,7 +13,7 @@ namespace MvcSample.Web.Models public User Dependent { get; set; } public bool Alive { get; set; } public string Password { get; set; } - + public string About { get; set; } public string Log { get; set; } } } \ No newline at end of file diff --git a/samples/MvcSample.Web/Views/Home/Create.cshtml b/samples/MvcSample.Web/Views/Home/Create.cshtml index 289f4a39e2..f7fdcc49e2 100644 --- a/samples/MvcSample.Web/Views/Home/Create.cshtml +++ b/samples/MvcSample.Web/Views/Home/Create.cshtml @@ -67,6 +67,14 @@ @Html.DropDownListFor(model => model.Age, (IEnumerable)ViewBag.Ages, htmlAttributes: new { @class = "form-control" }) + + + + + + @Html.TextArea("About", "You can explain about your profession, hobbies etc.", 5, 40, htmlAttributes: new { style = "font-weight:bold" }) + + diff --git a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs index 3315f9b318..c291a3c46e 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Properties/Resources.Designer.cs @@ -906,6 +906,22 @@ namespace Microsoft.AspNet.Mvc.Core return GetString("AuthorizeAttribute_OnAuthorizationNotImplemented"); } + /// + /// The value must be greater than or equal to zero.. + /// + internal static string HtmlHelper_TextAreaParameterOutOfRange + { + get { return GetString("HtmlHelper_TextAreaParameterOutOfRange"); } + } + + /// + /// The value must be greater than or equal to zero.. + /// + internal static string FormatHtmlHelper_TextAreaParameterOutOfRange() + { + return GetString("HtmlHelper_TextAreaParameterOutOfRange"); + } + private static string GetString(string name, params string[] formatterNames) { var value = _resourceManager.GetString(name); diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs index ab29ffffbf..e39a0dfc28 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelper.cs @@ -513,6 +513,18 @@ namespace Microsoft.AspNet.Mvc.Rendering } } + /// + public virtual HtmlString TextArea(string name, string value, int rows, int columns, object htmlAttributes) + { + var metadata = ExpressionMetadataProvider.FromStringExpression(name, ViewData, MetadataProvider); + if (value != null) + { + metadata.Model = value; + } + + return GenerateTextArea(metadata, name, rows, columns, htmlAttributes); + } + /// public HtmlString TextBox(string name, object value, string format, IDictionary htmlAttributes) { @@ -959,48 +971,65 @@ namespace Microsoft.AspNet.Mvc.Rendering return tagBuilder.ToHtmlString(TagRenderMode.Normal); } - internal static MvcHtmlString TextAreaHelper(HtmlHelper htmlHelper, ModelMetadata modelMetadata, string name, IDictionary rowsAndColumns, IDictionary htmlAttributes, string innerHtmlPrefix = null) + protected virtual HtmlString GenerateTextArea(ModelMetadata metadata, string name, + int rows, int columns, object htmlAttributes) { - string fullName = htmlHelper.ViewContext.ViewData.TemplateInfo.GetFullHtmlFieldName(name); - if (String.IsNullOrEmpty(fullName)) + if (rows < 0) { - throw new ArgumentException(MvcResources.Common_NullOrEmpty, "name"); + throw new ArgumentOutOfRangeException("rows", Resources.HtmlHelper_TextAreaParameterOutOfRange); } - TagBuilder tagBuilder = new TagBuilder("textarea"); - tagBuilder.GenerateId(fullName); - tagBuilder.MergeAttributes(htmlAttributes, true); - tagBuilder.MergeAttributes(rowsAndColumns, rowsAndColumns != implicitRowsAndColumns); // Only force explicit rows/cols - tagBuilder.MergeAttribute("name", fullName, true); + if (columns < 0) + { + throw new ArgumentOutOfRangeException("columns", Resources.HtmlHelper_TextAreaParameterOutOfRange); + } + + var fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name); + if (string.IsNullOrEmpty(fullName)) + { + throw new ArgumentException(Resources.ArgumentCannotBeNullOrEmpty, "name"); + } - // If there are any errors for a named field, we add the CSS attribute. ModelState modelState; - if (htmlHelper.ViewData.ModelState.TryGetValue(fullName, out modelState) && modelState.Errors.Count > 0) - { - tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName); - } + ViewData.ModelState.TryGetValue(fullName, out modelState); - tagBuilder.MergeAttributes(htmlHelper.GetUnobtrusiveValidationAttributes(name, modelMetadata)); - - string value; + string value = string.Empty; if (modelState != null && modelState.Value != null) { value = modelState.Value.AttemptedValue; } - else if (modelMetadata.Model != null) + else if (metadata.Model != null) { - value = modelMetadata.Model.ToString(); + value = metadata.Model.ToString(); } - else + + var tagBuilder = new TagBuilder("textarea"); + tagBuilder.GenerateId(fullName, IdAttributeDotReplacement); + tagBuilder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes), true); + if (rows > 0) { - value = String.Empty; + tagBuilder.MergeAttribute("rows", rows.ToString(CultureInfo.InvariantCulture), true); + } + + if (columns > 0) + { + tagBuilder.MergeAttribute("columns", columns.ToString(CultureInfo.InvariantCulture), true); + } + + tagBuilder.MergeAttribute("name", fullName, true); + tagBuilder.MergeAttributes(GetValidationAttributes(name, metadata)); + + // If there are any errors for a named field, we add this CSS attribute. + if (modelState != null && modelState.Errors.Count > 0) + { + tagBuilder.AddCssClass(HtmlHelper.ValidationInputCssClassName); } // The first newline is always trimmed when a TextArea is rendered, so we add an extra one // in case the value being rendered is something like "\r\nHello". - tagBuilder.InnerHtml = (innerHtmlPrefix ?? Environment.NewLine) + HttpUtility.HtmlEncode(value); + tagBuilder.InnerHtml = WebUtility.HtmlEncode(value); - return tagBuilder.ToMvcHtmlString(TagRenderMode.Normal); + return tagBuilder.ToHtmlString(TagRenderMode.Normal); } protected virtual HtmlString GenerateTextBox(ModelMetadata metadata, string name, object value, string format, diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelperOfT.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelperOfT.cs index ce6bf60c40..ad32c4e014 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelperOfT.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/Html/HtmlHelperOfT.cs @@ -166,6 +166,14 @@ namespace Microsoft.AspNet.Mvc.Rendering htmlAttributes: htmlAttributes); } + /// + public HtmlString TextAreaFor([NotNull] Expression> expression, int rows, + int columns, object htmlAttributes) + { + var metadata = GetModelMetadata(expression); + return GenerateTextArea(metadata, GetExpressionName(expression), rows, columns, htmlAttributes); + } + /// public HtmlString TextBoxFor([NotNull] Expression> expression, string format, IDictionary htmlAttributes) diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperInputExtensions.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperInputExtensions.cs index 1d50073b3e..f59c443d28 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperInputExtensions.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/HtmlHelperInputExtensions.cs @@ -184,5 +184,53 @@ namespace Microsoft.AspNet.Mvc.Rendering { return htmlHelper.TextBoxFor(expression, format: null, htmlAttributes: htmlAttributes); } + + public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper, + string name) + { + return htmlHelper.TextArea(name, value: null, rows: 0, columns: 0, htmlAttributes: null); + } + + public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper, + string name, object htmlAttributes) + { + return htmlHelper.TextArea(name, value: null, rows: 0, columns:0, htmlAttributes: htmlAttributes); + } + + public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper, + string name, string value) + { + return htmlHelper.TextArea(name, value, rows: 0, columns: 0, htmlAttributes: null); + } + + public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper, + string name, string value, object htmlAttributes) + { + return htmlHelper.TextArea(name, value, rows: 0, columns: 0, htmlAttributes: htmlAttributes); + } + + public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper, + string name, string value, int rows, int columns, object htmlAttributes) + { + return htmlHelper.TextArea(name, value, rows, columns, htmlAttributes); + } + + public static HtmlString TextAreaFor([NotNull] this IHtmlHelper htmlHelper, + [NotNull] Expression> expression) + { + return htmlHelper.TextAreaFor(expression, rows: 0, columns: 0, htmlAttributes: null); + } + + public static HtmlString TextAreaFor([NotNull] this IHtmlHelper htmlHelper, + [NotNull] Expression> expression, object htmlAttributes) + { + return htmlHelper.TextAreaFor(expression, rows: 0, columns: 0, htmlAttributes: htmlAttributes); + } + + public static HtmlString TextAreaFor([NotNull] this IHtmlHelper htmlHelper, + [NotNull] Expression> expression, int rows, int columns, object htmlAttributes) + { + return htmlHelper.TextAreaFor(expression, rows, columns, htmlAttributes); + } } } diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs index ea18514143..fe18fff9bc 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelper.cs @@ -341,6 +341,24 @@ namespace Microsoft.AspNet.Mvc.Rendering /// A task that represents when rendering has completed. Task RenderPartialAsync([NotNull] string partialViewName, object model, ViewDataDictionary viewData); + /// + /// Render a textarea. + /// + /// + /// Rendered element's name. Also use this name to find value in submitted data or view data. Use view data + /// only if value is not in submitted data and is null. + /// + /// + /// If non-null, value to include in the element. Ignore if named value is found in submitted data. + /// + /// Number of rows in the textarea. + /// Number of columns in the textarea. + /// + /// containing additional HTML attributes. + /// + /// New containing the rendered HTML. + HtmlString TextArea(string name, string value, int rows, int columns, object htmlAttributes); + /// /// Render an input element of type "text". /// diff --git a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelperOfT.cs b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelperOfT.cs index f79063c5a8..1aea63244d 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelperOfT.cs +++ b/src/Microsoft.AspNet.Mvc.Core/Rendering/IHtmlHelperOfT.cs @@ -177,6 +177,19 @@ namespace Microsoft.AspNet.Mvc.Rendering HtmlString RadioButtonFor([NotNull] Expression> expression, object value, object htmlAttributes); + /// + /// Render a textarea. + /// + /// An expression, relative to the current model. + /// Number of rows in the textarea. + /// Number of columns in the textarea. + /// + /// containing additional HTML attributes. + /// + /// New containing the rendered HTML. + HtmlString TextAreaFor([NotNull] Expression> expression, + int rows, int columns, object htmlAttributes); + /// /// Render an input element of type "text". /// diff --git a/src/Microsoft.AspNet.Mvc.Core/Resources.resx b/src/Microsoft.AspNet.Mvc.Core/Resources.resx index f65d02edd1..92a8fe7ec4 100644 --- a/src/Microsoft.AspNet.Mvc.Core/Resources.resx +++ b/src/Microsoft.AspNet.Mvc.Core/Resources.resx @@ -285,4 +285,7 @@ OnAuthorization is not implemented by this filter, use OnAuthorizationAsync instead. - + + The value must be greater than or equal to zero. + + \ No newline at end of file