Remove HTML helpers with `IDictionary<string, object>` parameters

- see line 2 of #874
- focus on `TextBox[For]()` and `ValidationSummary()`

related fixes included here:
- `TextArea[For]()` documentation incorrectly indicated their `htmlAttributes` parameters were dictionaries
- handle `htmlAttributes` parameters more consistently; create a dictionary only when necessary
This commit is contained in:
dougbu 2014-08-03 22:37:42 -07:00
parent c9b2323592
commit 3db0a80306
6 changed files with 62 additions and 132 deletions

View File

@ -115,7 +115,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes)
{
var url = _urlHelper.Action(actionName, controllerName, routeValues);
return GenerateLink(linkText, url, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
return GenerateLink(linkText, url, GetHtmlAttributeDictionaryOrNull(htmlAttributes));
}
/// <summary>
@ -186,13 +186,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public MvcForm BeginForm(string actionName, string controllerName, object routeValues, FormMethod method,
object htmlAttributes)
{
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes);
}
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
return GenerateForm(actionName, controllerName, routeValues, method, htmlAttributeDictionary);
}
@ -427,7 +421,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes)
{
var url = _urlHelper.RouteUrl(routeName, routeValues, protocol, hostName, fragment);
return GenerateLink(linkText, url, HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
return GenerateLink(linkText, url, GetHtmlAttributeDictionaryOrNull(htmlAttributes));
}
/// <inheritdoc />
@ -437,12 +431,17 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <inheritdoc />
public HtmlString ValidationSummary(bool excludePropertyErrors,
public HtmlString ValidationSummary(
bool excludePropertyErrors,
string message,
IDictionary<string, object> htmlAttributes,
object htmlAttributes,
string tag)
{
return GenerateValidationSummary(excludePropertyErrors, message, htmlAttributes, tag);
return GenerateValidationSummary(
excludePropertyErrors,
message,
GetHtmlAttributeDictionaryOrNull(htmlAttributes),
tag);
}
/// <summary>
@ -476,7 +475,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
/// <inheritdoc />
public HtmlString TextBox(string name, object value, string format, IDictionary<string, object> htmlAttributes)
public HtmlString TextBox(string name, object value, string format, object htmlAttributes)
{
return GenerateTextBox(metadata: null, name: name, value: value, format: format,
htmlAttributes: htmlAttributes);
@ -563,17 +562,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
}
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
var explicitValue = isChecked.HasValue;
if (explicitValue && htmlAttributeDictionary != null)
{
@ -691,17 +680,6 @@ namespace Microsoft.AspNet.Mvc.Rendering
bool useViewData,
object htmlAttributes)
{
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
// Special-case opaque values and arbitrary binary data.
var byteArrayValue = value as byte[];
if (byteArrayValue != null)
@ -709,6 +687,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
value = Convert.ToBase64String(byteArrayValue);
}
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
return GenerateInput(InputType.Hidden,
metadata,
name,
@ -750,7 +729,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
ViewData.TemplateInfo.GetFullHtmlFieldName(htmlFieldName),
IdAttributeDotReplacement));
tag.SetInnerText(resolvedLabelText);
tag.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes), replaceExisting: true);
tag.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes), replaceExisting: true);
return tag.ToHtmlString(TagRenderMode.Normal);
}
@ -794,17 +773,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
protected virtual HtmlString GeneratePassword(ModelMetadata metadata, string name, object value,
object htmlAttributes)
{
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
return GenerateInput(InputType.Password,
metadata,
name,
@ -820,17 +789,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
protected virtual HtmlString GenerateRadioButton(ModelMetadata metadata, string name, object value,
bool? isChecked, object htmlAttributes)
{
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
if (metadata == null)
{
// RadioButton() case. Do not override checked attribute if isChecked is implicit.
@ -941,7 +900,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
{
InnerHtml = listItemBuilder.ToString()
};
tagBuilder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes));
tagBuilder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes));
tagBuilder.MergeAttribute("name", fullName, true /* replaceExisting */);
tagBuilder.GenerateId(fullName, IdAttributeDotReplacement);
if (allowMultiple)
@ -998,7 +957,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
var tagBuilder = new TagBuilder("textarea");
tagBuilder.GenerateId(fullName, IdAttributeDotReplacement);
tagBuilder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes), true);
tagBuilder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes), true);
if (rows > 0)
{
tagBuilder.MergeAttribute("rows", rows.ToString(CultureInfo.InvariantCulture), true);
@ -1026,8 +985,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
}
protected virtual HtmlString GenerateTextBox(ModelMetadata metadata, string name, object value, string format,
IDictionary<string, object> htmlAttributes)
object htmlAttributes)
{
var htmlAttributeDictionary = GetHtmlAttributeDictionaryOrNull(htmlAttributes);
return GenerateInput(InputType.Text,
metadata,
name,
@ -1037,7 +997,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
setId: true,
isExplicitValue: true,
format: format,
htmlAttributes: htmlAttributes);
htmlAttributes: htmlAttributeDictionary);
}
protected virtual HtmlString GenerateInput(InputType inputType, ModelMetadata metadata, string name,
@ -1189,7 +1149,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
tag = ViewContext.ValidationMessageElement;
}
var builder = new TagBuilder(tag);
builder.MergeAttributes(AnonymousObjectToHtmlAttributes(htmlAttributes));
builder.MergeAttributes(GetHtmlAttributeDictionaryOrNull(htmlAttributes));
// Only the style of the span is changed according to the errors if message is null or empty.
// Otherwise the content and style is handled by the client-side validation.
@ -1349,6 +1309,22 @@ namespace Microsoft.AspNet.Mvc.Rendering
new ClientModelValidationContext(metadata, MetadataProvider)));
}
// Only need a dictionary if htmlAttributes is non-null. TagBuilder.MergeAttributes() is fine with null.
private static IDictionary<string, object> GetHtmlAttributeDictionaryOrNull(object htmlAttributes)
{
IDictionary<string, object> htmlAttributeDictionary = null;
if (htmlAttributes != null)
{
htmlAttributeDictionary = htmlAttributes as IDictionary<string, object>;
if (htmlAttributeDictionary == null)
{
htmlAttributeDictionary = AnonymousObjectToHtmlAttributes(htmlAttributes);
}
}
return htmlAttributeDictionary;
}
private static string GetInputTypeString(InputType inputType)
{
switch (inputType)

View File

@ -206,7 +206,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <inheritdoc />
public HtmlString TextBoxFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
string format, IDictionary<string, object> htmlAttributes)
string format, object htmlAttributes)
{
var metadata = GetModelMetadata(expression);
return GenerateTextBox(metadata, GetExpressionName(expression), metadata.Model, format, htmlAttributes);

View File

@ -144,17 +144,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
string format,
object htmlAttributes)
{
return htmlHelper.TextBox(name, value, format,
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static HtmlString TextBox(
[NotNull] this IHtmlHelper htmlHelper,
string name,
object value,
IDictionary<string, object> htmlAttributes)
{
return htmlHelper.TextBox(name, value, format: null, htmlAttributes: htmlAttributes);
return htmlHelper.TextBox(name, value, format, htmlAttributes);
}
public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
@ -178,14 +168,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression, string format, object htmlAttributes)
{
return htmlHelper.TextBoxFor(expression, format: format,
htmlAttributes: HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes));
}
public static HtmlString TextBoxFor<TModel, TProperty>([NotNull] this IHtmlHelper<TModel> htmlHelper,
[NotNull] Expression<Func<TModel, TProperty>> expression, IDictionary<string, object> htmlAttributes)
{
return htmlHelper.TextBoxFor(expression, format: null, htmlAttributes: htmlAttributes);
return htmlHelper.TextBoxFor(expression, format: format, htmlAttributes: htmlAttributes);
}
public static HtmlString TextArea([NotNull] this IHtmlHelper htmlHelper,

View File

@ -138,10 +138,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
string message,
object htmlAttributes)
{
return htmlHelper.ValidationSummary(excludePropertyErrors: false,
message: message,
htmlAttributes: HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag: null);
return htmlHelper.ValidationSummary(
excludePropertyErrors: false, message: message, htmlAttributes: htmlAttributes, tag: null);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
@ -149,10 +147,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes,
string tag)
{
return htmlHelper.ValidationSummary(excludePropertyErrors: false,
message: message,
htmlAttributes: HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag: tag);
return htmlHelper.ValidationSummary(
excludePropertyErrors: false, message: message, htmlAttributes: htmlAttributes, tag: tag);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
@ -171,10 +167,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
string message,
object htmlAttributes)
{
return htmlHelper.ValidationSummary(excludePropertyErrors,
message,
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag: null);
return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes, tag: null);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
@ -183,31 +176,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
object htmlAttributes,
string tag)
{
return htmlHelper.ValidationSummary(excludePropertyErrors,
message,
HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributes),
tag);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
string message,
IDictionary<string, object> htmlAttributes)
{
return htmlHelper.ValidationSummary(excludePropertyErrors: false,
message: message,
htmlAttributes: htmlAttributes,
tag: null);
}
public static HtmlString ValidationSummary([NotNull] this IHtmlHelper htmlHelper,
string message,
IDictionary<string, object> htmlAttributes,
string tag)
{
return htmlHelper.ValidationSummary(excludePropertyErrors: false,
message: message,
htmlAttributes: htmlAttributes,
tag: tag);
return htmlHelper.ValidationSummary(excludePropertyErrors, message, htmlAttributes, tag);
}
}
}

View File

@ -414,8 +414,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// </param>
/// <param name="rows">Number of rows in the textarea.</param>
/// <param name="columns">Number of columns in the textarea.</param>
/// <param name="htmlAttributes">
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes.
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextArea(string name, string value, int rows, int columns, object htmlAttributes);
@ -431,11 +431,11 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// If non-<c>null</c>, value to include in the element. Ignore if named value is found in submitted data.
/// </param>
/// <param name="format"></param>
/// <param name="htmlAttributes">
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes.
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextBox(string name, object value, string format, IDictionary<string, object> htmlAttributes);
HtmlString TextBox(string name, object value, string format, object htmlAttributes);
/// <summary>
/// Returns the validation message if an error exists in the <see cref="ModelStateDictionary"/> object.
@ -458,7 +458,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <param name="excludePropertyErrors">true to have the summary display model-level errors only, or false to
/// have the summary display all errors.</param>
/// <param name="message">The message to display with the validation summary.</param>
/// <param name="htmlAttributes">A dictionary that contains the HTML attributes for the element.</param>
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <param name="tag">The tag to wrap the <paramref name="message"/> in the generated HTML.
/// Its default value is <see cref="ViewContext.ValidationMessageElement" />.</param>
/// <returns>An <see cref="HtmlString"/> that contains an unordered list (ul element) of validation messages.
@ -466,7 +468,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
HtmlString ValidationSummary(
bool excludePropertyErrors,
string message,
IDictionary<string, object> htmlAttributes,
object htmlAttributes,
string tag);
/// <summary>

View File

@ -223,8 +223,8 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// <param name="expression">An expression, relative to the current model.</param>
/// <param name="rows">Number of rows in the textarea.</param>
/// <param name="columns">Number of columns in the textarea.</param>
/// <param name="htmlAttributes">
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes.
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextAreaFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
@ -237,12 +237,12 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// An expression that identifies the object that contains the properties to render.
/// </param>
/// <param name="format"></param>
/// <param name="htmlAttributes">
/// <see cref="IDictionary{string, object}"/> containing additional HTML attributes.
/// <param name="htmlAttributes">An object that contains the HTML attributes to set for the element.
/// Alternatively, an <see cref="IDictionary{string, object}"/> instance containing the HTML attributes.
/// </param>
/// <returns>New <see cref="HtmlString"/> containing the rendered HTML.</returns>
HtmlString TextBoxFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression, string format,
IDictionary<string, object> htmlAttributes);
object htmlAttributes);
/// <summary>
/// Returns the validation message for the specified expression