Implement `Editor*()` HTML helpers

- copy over legacy `Editor*()` extensions and default editor templates
- get working in the new world
 - usual `var`, `String` -> `string`, `internal` -> `public`, namespaces, ...
 - longest overloads into `IHtmlHelper[<TModel>]` and implementation classes
 - clean up `ViewContext.ViewData` -> `ViewData`, trailing whitespace, long lines
 - remove `MultilineTextTemplate()` since `TextArea()` doesn't exist yet
 - remove `ColorInputTemplate()` since `Color` type doesn't exist
 - use `html.Label()`, not `LabelExtensions.LabelHelper()`: equivalent helper
   is protected.  only downside is potential `ModelMetadata` re-discovery.
 - rename `HtmlInputTemplateHelper()` -> `GenerateTextBox()`
- copy over `Html5DateRenderingMode` and `html.Html5DateRenderingMode` property
 - and get them working in new world
- hook the default editor templates up
- use `Editor()`, `EditorFor()`, `EditorForModel()` in MVC sample
 - add an on-disk editor template to MVC sample
This commit is contained in:
dougbu 2014-04-20 00:40:12 -07:00
parent b3046a0285
commit f7704ba68f
12 changed files with 696 additions and 23 deletions

View File

@ -29,6 +29,7 @@
<Content Include="Views\Link\Details.cshtml" />
<Content Include="Views\Shared\Components\Tags\Default.cshtml" />
<Content Include="Views\Shared\DisplayTemplates\Decimal.cshtml" />
<Content Include="Views\Shared\EditorTemplates\Decimal.cshtml" />
<Content Include="Views\Shared\HelloWorldPartial.cshtml" />
<Content Include="Views\Shared\MyView.cshtml" />
<Content Include="Views\Shared\_Layout.cshtml" />

View File

@ -0,0 +1,18 @@
@* Override default Decimal template to display value in bold and ignore Html attributes in ViewData. *@
@using System.Globalization
@functions {
private object FormattedValue {
get {
if (ViewData.TemplateInfo.FormattedModelValue == ViewData.ModelMetadata.Model) {
return string.Format(CultureInfo.CurrentCulture, "{0:0.00}", ViewData.ModelMetadata.Model);
}
return ViewData.TemplateInfo.FormattedModelValue;
}
}
}
@Html.TextBox(
name: string.Empty,
value: FormattedValue,
htmlAttributes: new { @class = "text-box single-line", style = "font-weight: bold", })

View File

@ -270,111 +270,156 @@
@{ Html.EndForm(); }
</div>
<div style="float: left; border: 5px solid lightgreen; margin: 5px; padding: 7px;">
@using (Html.BeginForm(controllerName: "Home", actionName: "Edit", method: FormMethod.Post))
{
<table>
<tr>
<td>
@Html.Label("Name", "Display Name")
@Html.Label("Name", "Display / Edit Name")
</td>
<td>
'@Html.Display("Name")'
</td>
<td>
@Html.Editor("Name")
</td>
</tr>
<tr>
<td>
@Html.Label("Dependent.Name", "Display Dependent.Name")
@Html.Label("Dependent.Name", "Display / Edit Dependent.Name")
</td>
<td>
'@Html.Display("Dependent.Name")'
</td>
<td>
@Html.Editor("Dependent.Name")
</td>
</tr>
<tr>
<td>
@Html.Label("Alive", "Display Alive")
@Html.Label("Alive", "Display / Edit Alive")
</td>
<td>
'@Html.Display("Alive")'
</td>
<td>
@Html.Editor("Alive")
</td>
</tr>
<tr>
<td>
@Html.Label("Dependent.Alive", "Display Dependent.Alive")
@Html.Label("Dependent.Alive", "Display / Edit Dependent.Alive")
</td>
<td>
'@Html.Display("Dependent.Alive")'
</td>
<td>
@Html.Editor("Dependent.Alive")
</td>
</tr>
<tr>
<td>
@Html.Label("Age", "Display Age")
@Html.Label("Age", "Display / Edit Age")
</td>
<td>
'@Html.Display("Age")'
</td>
<td>
@Html.Editor("Age")
</td>
</tr>
<tr>
<td>
@Html.Label("GPA", "Display GPA")
@Html.Label("GPA", "Display / Edit GPA")
</td>
<td>
'@Html.Display("GPA")'
</td>
<td>
@Html.Editor("GPA")
</td>
</tr>
</table>
}
</div>
<div style="float: left; border: 5px dashed green; margin: 5px; padding: 7px;">
@using (Html.BeginForm(controllerName: "Home", actionName: "Edit", method: FormMethod.Post))
{
<table>
<tr>
<td>
@Html.LabelFor(model => model.Name, "DisplayFor Name")
@Html.LabelFor(model => model.Name, "DisplayFor / EditFor Name")
</td>
<td>
'@Html.DisplayFor(model => model.Name)'
</td>
<td>
@Html.EditorFor(model => model.Name)
</td>
</tr>
<tr>
<td>
@Html.LabelFor(model => model.Dependent.Name, "DisplayFor Dependent.Name")
@Html.LabelFor(model => model.Dependent.Name, "DisplayFor / EditFor Dependent.Name")
</td>
<td>
'@Html.DisplayFor(model => model.Dependent.Name)'
</td>
<td>
@Html.EditorFor(model => model.Dependent.Name)
</td>
</tr>
<tr>
<td>
@Html.LabelFor(model => model.Alive, "DisplayFor Alive")
@Html.LabelFor(model => model.Alive, "DisplayFor / EditFor Alive")
</td>
<td>
'@Html.DisplayFor(model => model.Alive)'
</td>
<td>
@Html.EditorFor(model => model.Alive)
</td>
</tr>
<tr>
<td>
@Html.LabelFor(model => model.Dependent.Alive, "DisplayFor Dependent.Alive")
@Html.LabelFor(model => model.Dependent.Alive, "DisplayFor / EditFor Dependent.Alive")
</td>
<td>
'@Html.DisplayFor(model => model.Dependent.Alive)'
</td>
<td>
@Html.EditorFor(model => model.Dependent.Alive)
</td>
</tr>
<tr>
<td>
@Html.LabelFor(model => model.Age, "DisplayFor Age")
@Html.LabelFor(model => model.Age, "DisplayFor / EditFor Age")
</td>
<td>
'@Html.DisplayFor(model => model.Age)'
</td>
<td>
@Html.EditorFor(model => model.Age)
</td>
</tr>
<tr>
<td>
@Html.LabelFor(model => model.GPA, "DisplayFor GPA")
@Html.LabelFor(model => model.GPA, "DisplayFor / EditFor GPA")
</td>
<td>
'@Html.DisplayFor(model => model.GPA)'
</td>
<td>
@Html.EditorFor(model => model.GPA)
</td>
</tr>
</table>
}
</div>
<div style="float: left; border: 5px solid darkgreen; margin: 5px; padding: 7px;">
<div style="float: left; border: 5px solid darkseagreen; margin: 5px; padding: 7px;">
@Html.DisplayForModel()
</div>
<div style="float: left; border: 5px dotted darkgreen; margin: 5px; padding: 7px">
@Html.EditorForModel()
</div>
</div>

View File

@ -159,8 +159,10 @@
<Compile Include="Rendering\Expressions\ViewDataEvaluator.cs" />
<Compile Include="Rendering\Expressions\ViewDataInfo.cs" />
<Compile Include="Rendering\FormMethod.cs" />
<Compile Include="Rendering\Html5DateRenderingMode.cs" />
<Compile Include="Rendering\HtmlAttributePropertyHelper.cs" />
<Compile Include="Rendering\HtmlHelperDisplayExtensions.cs" />
<Compile Include="Rendering\HtmlHelperEditorExtensions.cs" />
<Compile Include="Rendering\HtmlHelperFormExtensions.cs" />
<Compile Include="Rendering\HtmlHelperInputExtensions.cs" />
<Compile Include="Rendering\HtmlHelperLabelExtensions.cs" />
@ -173,6 +175,7 @@
<Compile Include="Rendering\HtmlHelperValueExtensions.cs" />
<Compile Include="Rendering\HtmlString.cs" />
<Compile Include="Rendering\Html\DefaultDisplayTemplates.cs" />
<Compile Include="Rendering\Html\DefaultEditorTemplates.cs" />
<Compile Include="Rendering\Html\HtmlHelper.cs" />
<Compile Include="Rendering\Html\HtmlHelperOfT.cs" />
<Compile Include="Rendering\Html\InputType.cs" />

View File

@ -0,0 +1,363 @@
using System;
using System.Collections;
using System.Collections.Generic;
using System.Globalization;
using System.Linq;
using System.Text;
using Microsoft.AspNet.DependencyInjection;
using Microsoft.AspNet.Mvc.Core;
using Microsoft.AspNet.Mvc.ModelBinding;
namespace Microsoft.AspNet.Mvc.Rendering
{
public static class DefaultEditorTemplates
{
private const string HtmlAttributeKey = "htmlAttributes";
public static string BooleanTemplate(IHtmlHelper html)
{
bool? value = null;
if (html.ViewData.Model != null)
{
value = Convert.ToBoolean(html.ViewData.Model, CultureInfo.InvariantCulture);
}
return html.ViewData.ModelMetadata.IsNullableValueType ?
BooleanTemplateDropDownList(html, value) :
BooleanTemplateCheckbox(html, value ?? false);
}
private static string BooleanTemplateCheckbox(IHtmlHelper html, bool value)
{
return html.CheckBox(string.Empty, value, CreateHtmlAttributes(html, "check-box")).ToString();
}
private static string BooleanTemplateDropDownList(IHtmlHelper html, bool? value)
{
return html.DropDownList(
string.Empty,
DefaultDisplayTemplates.TriStateValues(value),
CreateHtmlAttributes(html, "list-box tri-state"))
.ToString();
}
public static string CollectionTemplate(IHtmlHelper html)
{
var viewData = html.ViewData;
var model = viewData.ModelMetadata.Model;
if (model == null)
{
return string.Empty;
}
var collection = model as IEnumerable;
if (collection == null)
{
// Only way we could reach here is if user passed templateName: "Collection" to an Editor() overload.
throw new InvalidOperationException(Resources.FormatTemplates_TypeMustImplementIEnumerable(
"Collection", model.GetType().FullName, typeof(IEnumerable).FullName));
}
var typeInCollection = typeof(string);
var genericEnumerableType = collection.GetType().ExtractGenericInterface(typeof(IEnumerable<>));
if (genericEnumerableType != null)
{
typeInCollection = genericEnumerableType.GetGenericArguments()[0];
}
var typeInCollectionIsNullableValueType = typeInCollection.IsNullableValueType();
var oldPrefix = viewData.TemplateInfo.HtmlFieldPrefix;
try
{
viewData.TemplateInfo.HtmlFieldPrefix = string.Empty;
var fieldNameBase = oldPrefix;
var result = new StringBuilder();
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var metadataProvider = serviceProvider.GetService<IModelMetadataProvider>();
var viewEngine = serviceProvider.GetService<IViewEngine>();
var index = 0;
foreach (var item in collection)
{
var itemType = typeInCollection;
if (item != null && !typeInCollectionIsNullableValueType)
{
itemType = item.GetType();
}
var metadata = metadataProvider.GetMetadataForType(() => item, itemType);
var fieldName = string.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++);
var templateBuilder = new TemplateBuilder(
viewEngine,
html.ViewContext,
html.ViewData,
metadata,
htmlFieldName: fieldName,
templateName: null,
readOnly: false,
additionalViewData: null);
var output = templateBuilder.Build();
result.Append(output);
}
return result.ToString();
}
finally
{
viewData.TemplateInfo.HtmlFieldPrefix = oldPrefix;
}
}
public static string DecimalTemplate(IHtmlHelper html)
{
if (html.ViewData.TemplateInfo.FormattedModelValue == html.ViewData.ModelMetadata.Model)
{
html.ViewData.TemplateInfo.FormattedModelValue =
string.Format(CultureInfo.CurrentCulture, "{0:0.00}", html.ViewData.ModelMetadata.Model);
}
return StringTemplate(html);
}
public static string HiddenInputTemplate(IHtmlHelper html)
{
var viewData = html.ViewData;
// TODO: add ModelMetadata.HideSurroundingHtml and use here (set result to string.Empty)
var result = DefaultDisplayTemplates.StringTemplate(html);
var model = viewData.Model;
// Special-case opaque values and arbitrary binary data.
var modelAsByteArray = model as byte[];
if (modelAsByteArray != null)
{
model = Convert.ToBase64String(modelAsByteArray);
}
var htmlAttributesObject = viewData[HtmlAttributeKey];
var hiddenResult = html.Hidden(string.Empty, model, htmlAttributesObject);
result += hiddenResult.ToString();
return result;
}
private static IDictionary<string, object> CreateHtmlAttributes(
IHtmlHelper html,
string className,
string inputType = null)
{
var htmlAttributesObject = html.ViewData[HtmlAttributeKey];
if (htmlAttributesObject != null)
{
return MergeHtmlAttributes(htmlAttributesObject, className, inputType);
}
var htmlAttributes = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase)
{
{ "class", className }
};
if (inputType != null)
{
htmlAttributes.Add("type", inputType);
}
return htmlAttributes;
}
private static IDictionary<string, object> MergeHtmlAttributes(
object htmlAttributesObject,
string className,
string inputType)
{
var htmlAttributes = HtmlHelper.AnonymousObjectToHtmlAttributes(htmlAttributesObject);
object htmlClassObject;
if (htmlAttributes.TryGetValue("class", out htmlClassObject))
{
var htmlClassName = htmlClassObject.ToString() + " " + className;
htmlAttributes["class"] = htmlClassName;
}
else
{
htmlAttributes.Add("class", className);
}
// The input type from the provided htmlAttributes overrides the inputType parameter.
if (inputType != null && !htmlAttributes.ContainsKey("type"))
{
htmlAttributes.Add("type", inputType);
}
return htmlAttributes;
}
public static string ObjectTemplate(IHtmlHelper html)
{
var viewData = html.ViewData;
var templateInfo = viewData.TemplateInfo;
var modelMetadata = viewData.ModelMetadata;
var builder = new StringBuilder();
if (templateInfo.TemplateDepth > 1)
{
// TODO: add ModelMetadata.SimpleDisplayText and use here (return SimpleDisplayText, not ToString())
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.Model.ToString();
}
var serviceProvider = html.ViewContext.HttpContext.RequestServices;
var viewEngine = serviceProvider.GetService<IViewEngine>();
foreach (var propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
{
var divTag = new TagBuilder("div");
// TODO: add ModelMetadata.HideSurroundingHtml and use here (skip this block)
{
var label = html.Label(propertyMetadata.PropertyName).ToString();
if (!string.IsNullOrEmpty(label))
{
divTag.AddCssClass("editor-label");
divTag.InnerHtml = label; // already escaped
builder.AppendLine(divTag.ToString(TagRenderMode.Normal));
// Reset divTag for reuse.
divTag.Attributes.Clear();
}
divTag.AddCssClass("editor-field");
builder.Append(divTag.ToString(TagRenderMode.StartTag));
}
var templateBuilder = new TemplateBuilder(
viewEngine,
html.ViewContext,
html.ViewData,
propertyMetadata,
htmlFieldName: propertyMetadata.PropertyName,
templateName: null,
readOnly: false,
additionalViewData: null);
builder.Append(templateBuilder.Build());
// TODO: add ModelMetadata.HideSurroundingHtml and use here (skip this block)
// TODO: Add IHtmlHelper.ValidationMessage() and call just prior to closing the <div/> tag
{
builder.Append(" ");
builder.AppendLine(divTag.ToString(TagRenderMode.EndTag));
}
}
return builder.ToString();
}
public static string PasswordTemplate(IHtmlHelper html)
{
return html.Password(string.Empty,
html.ViewData.TemplateInfo.FormattedModelValue,
CreateHtmlAttributes(html, "text-box single-line password"))
.ToString();
}
private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
{
// TODO: add ModelMetadata.ShowForEdit and include in this calculation (first)
return
!metadata.IsComplexType
&& !templateInfo.Visited(metadata);
}
public static string StringTemplate(IHtmlHelper html)
{
return GenerateTextBox(html);
}
public static string PhoneNumberInputTemplate(IHtmlHelper html)
{
return GenerateTextBox(html, inputType: "tel");
}
public static string UrlInputTemplate(IHtmlHelper html)
{
return GenerateTextBox(html, inputType: "url");
}
public static string EmailAddressInputTemplate(IHtmlHelper html)
{
return GenerateTextBox(html, inputType: "email");
}
public static string DateTimeInputTemplate(IHtmlHelper html)
{
ApplyRfc3339DateFormattingIfNeeded(html, "{0:yyyy-MM-ddTHH:mm:ss.fffK}");
return GenerateTextBox(html, inputType: "datetime");
}
public static string DateTimeLocalInputTemplate(IHtmlHelper html)
{
ApplyRfc3339DateFormattingIfNeeded(html, "{0:yyyy-MM-ddTHH:mm:ss.fff}");
return GenerateTextBox(html, inputType: "datetime-local");
}
public static string DateInputTemplate(IHtmlHelper html)
{
ApplyRfc3339DateFormattingIfNeeded(html, "{0:yyyy-MM-dd}");
return GenerateTextBox(html, inputType: "date");
}
public static string TimeInputTemplate(IHtmlHelper html)
{
ApplyRfc3339DateFormattingIfNeeded(html, "{0:HH:mm:ss.fff}");
return GenerateTextBox(html, inputType: "time");
}
public static string NumberInputTemplate(IHtmlHelper html)
{
return GenerateTextBox(html, inputType: "number");
}
private static void ApplyRfc3339DateFormattingIfNeeded(IHtmlHelper html, string format)
{
if (html.Html5DateRenderingMode != Html5DateRenderingMode.Rfc3339)
{
return;
}
var metadata = html.ViewData.ModelMetadata;
var value = metadata.Model;
// TODO: add ModelMetadata.HasNonDefaultEditFormat and use here (also return if true)
if (html.ViewData.TemplateInfo.FormattedModelValue != value)
{
return;
}
if (value is DateTime || value is DateTimeOffset)
{
html.ViewData.TemplateInfo.FormattedModelValue =
string.Format(CultureInfo.InvariantCulture, format, value);
}
}
private static string GenerateTextBox(IHtmlHelper html, string inputType = null)
{
return GenerateTextBox(html, inputType, html.ViewData.TemplateInfo.FormattedModelValue);
}
private static string GenerateTextBox(IHtmlHelper html, string inputType, object value)
{
return html.TextBox(
name: string.Empty,
value: value,
htmlAttributes: CreateHtmlAttributes(html, className: "text-box single-line", inputType: inputType))
.ToString();
}
}
}

View File

@ -52,6 +52,9 @@ namespace Microsoft.AspNet.Mvc.Rendering
IdAttributeDotReplacement = "_";
}
/// <inheritdoc />
public Html5DateRenderingMode Html5DateRenderingMode { get; set; }
/// <inheritdoc />
public string IdAttributeDotReplacement { get; set; }
@ -273,6 +276,19 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributes);
}
/// <inheritdoc />
public HtmlString Editor(string expression, string templateName, string htmlFieldName,
object additionalViewData)
{
var metadata = ExpressionMetadataProvider.FromStringExpression(expression, ViewData, MetadataProvider);
return GenerateEditor(
metadata,
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
templateName,
additionalViewData);
}
/// <inheritdoc />
public HtmlString Hidden(string name, object value, object htmlAttributes)
{
@ -642,6 +658,24 @@ namespace Microsoft.AspNet.Mvc.Rendering
htmlAttributes: htmlAttributes);
}
protected virtual HtmlString GenerateEditor(ModelMetadata metadata, string htmlFieldName, string templateName,
object additionalViewData)
{
var templateBuilder = new TemplateBuilder(
_viewEngine,
ViewContext,
ViewData,
metadata,
htmlFieldName,
templateName,
readOnly: false,
additionalViewData: additionalViewData);
var templateResult = templateBuilder.Build();
return new HtmlString(templateResult);
}
/// <summary>
/// Writes an opening <form> tag to the response. When the user submits the form,
/// the request will be processed by an action method.

View File

@ -109,6 +109,22 @@ namespace Microsoft.AspNet.Mvc.Rendering
return GenerateDisplayName(metadata, expressionText);
}
/// <inheritdoc />
public HtmlString EditorFor<TValue>(
[NotNull] Expression<Func<TModel, TValue>> expression,
string templateName,
string htmlFieldName,
object additionalViewData)
{
var metadata = ExpressionMetadataProvider.FromLambdaExpression(expression, ViewData, MetadataProvider);
return GenerateEditor(
metadata,
htmlFieldName ?? ExpressionHelper.GetExpressionText(expression),
templateName,
additionalViewData);
}
/// <inheritdoc />
public HtmlString HiddenFor<TProperty>([NotNull] Expression<Func<TModel, TProperty>> expression,
object htmlAttributes)

View File

@ -29,6 +29,33 @@ namespace Microsoft.AspNet.Mvc.Rendering
{ typeof(object).Name, DefaultDisplayTemplates.ObjectTemplate },
};
// TODO: Add DefaultEditorTemplates.MultilineTextTemplate and place in this dictionary.
private static readonly Dictionary<string, Func<IHtmlHelper, string>> _defaultEditorActions =
new Dictionary<string, Func<IHtmlHelper, string>>(StringComparer.OrdinalIgnoreCase)
{
{ "HiddenInput", DefaultEditorTemplates.HiddenInputTemplate },
{ "Password", DefaultEditorTemplates.PasswordTemplate },
{ "Text", DefaultEditorTemplates.StringTemplate },
{ "Collection", DefaultEditorTemplates.CollectionTemplate },
{ "PhoneNumber", DefaultEditorTemplates.PhoneNumberInputTemplate },
{ "Url", DefaultEditorTemplates.UrlInputTemplate },
{ "EmailAddress", DefaultEditorTemplates.EmailAddressInputTemplate },
{ "DateTime", DefaultEditorTemplates.DateTimeInputTemplate },
{ "DateTime-local", DefaultEditorTemplates.DateTimeLocalInputTemplate },
{ "Date", DefaultEditorTemplates.DateInputTemplate },
{ "Time", DefaultEditorTemplates.TimeInputTemplate },
{ typeof(byte).Name, DefaultEditorTemplates.NumberInputTemplate },
{ typeof(sbyte).Name, DefaultEditorTemplates.NumberInputTemplate },
{ typeof(int).Name, DefaultEditorTemplates.NumberInputTemplate },
{ typeof(uint).Name, DefaultEditorTemplates.NumberInputTemplate },
{ typeof(long).Name, DefaultEditorTemplates.NumberInputTemplate },
{ typeof(ulong).Name, DefaultEditorTemplates.NumberInputTemplate },
{ typeof(bool).Name, DefaultEditorTemplates.BooleanTemplate },
{ typeof(decimal).Name, DefaultEditorTemplates.DecimalTemplate },
{ typeof(string).Name, DefaultEditorTemplates.StringTemplate },
{ typeof(object).Name, DefaultEditorTemplates.ObjectTemplate },
};
private ViewContext _viewContext;
private ViewDataDictionary _viewData;
private IViewEngine _viewEngine;
@ -89,16 +116,7 @@ namespace Microsoft.AspNet.Mvc.Rendering
private Dictionary<string, Func<IHtmlHelper, string>> GetDefaultActions()
{
if (_readOnly)
{
return _defaultDisplayActions;
}
else
{
// TODO: Support Editor() and its default templates.
// (No resource for this message because this line _must_ be very short-lived.)
throw new NotImplementedException("No default editor templates yet");
}
return _readOnly ? _defaultDisplayActions : _defaultEditorActions;
}
private IEnumerable<string> GetViewNames()

View File

@ -0,0 +1,21 @@

namespace Microsoft.AspNet.Mvc.Rendering
{
/// <summary>
/// Controls the value-rendering method For HTML5 input elements of types such as date, time, datetime and
/// datetime-local.
/// </summary>
public enum Html5DateRenderingMode
{
/// <summary>
/// Render date and time values according to the current culture's ToString behavior.
/// </summary>
CurrentCulture = 0,
/// <summary>
/// Render date and time values as Rfc3339 compliant strings to support HTML5 date and time types of input
/// elements.
/// </summary>
Rfc3339,
}
}

View File

@ -0,0 +1,105 @@
using System;
using System.Linq.Expressions;
namespace Microsoft.AspNet.Mvc.Rendering
{
public static class EditorExtensions
{
public static HtmlString Editor(this IHtmlHelper html, string expression)
{
return html.Editor(expression, templateName: null, htmlFieldName: null, additionalViewData: null);
}
public static HtmlString Editor(this IHtmlHelper html, string expression, object additionalViewData)
{
return html.Editor(expression, templateName: null, htmlFieldName: null,
additionalViewData: additionalViewData);
}
public static HtmlString Editor(this IHtmlHelper html, string expression, string templateName)
{
return html.Editor(expression, templateName, htmlFieldName: null, additionalViewData: null);
}
public static HtmlString Editor(this IHtmlHelper html, string expression, string templateName,
object additionalViewData)
{
return html.Editor(expression, templateName, htmlFieldName: null, additionalViewData: additionalViewData);
}
public static HtmlString Editor(this IHtmlHelper html, string expression, string templateName,
string htmlFieldName)
{
return html.Editor(expression, templateName, htmlFieldName, additionalViewData: null);
}
public static HtmlString EditorFor<TModel, TValue>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression)
{
return html.EditorFor(expression, templateName: null, htmlFieldName: null, additionalViewData: null);
}
public static HtmlString EditorFor<TModel, TValue>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression, object additionalViewData)
{
return html.EditorFor(expression, templateName: null, htmlFieldName: null,
additionalViewData: additionalViewData);
}
public static HtmlString EditorFor<TModel, TValue>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression, string templateName)
{
return html.EditorFor(expression, templateName, htmlFieldName: null, additionalViewData: null);
}
public static HtmlString EditorFor<TModel, TValue>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression, string templateName, object additionalViewData)
{
return html.EditorFor(expression, templateName, htmlFieldName: null,
additionalViewData: additionalViewData);
}
public static HtmlString EditorFor<TModel, TValue>(this IHtmlHelper<TModel> html,
Expression<Func<TModel, TValue>> expression, string templateName, string htmlFieldName)
{
return html.EditorFor(expression, templateName, htmlFieldName, additionalViewData: null);
}
public static HtmlString EditorForModel(this IHtmlHelper html)
{
return html.Editor(expression: string.Empty, templateName: null, htmlFieldName: null,
additionalViewData: null);
}
public static HtmlString EditorForModel(this IHtmlHelper html, object additionalViewData)
{
return html.Editor(expression: string.Empty, templateName: null, htmlFieldName: null,
additionalViewData: additionalViewData);
}
public static HtmlString EditorForModel(this IHtmlHelper html, string templateName)
{
return html.Editor(expression: string.Empty, templateName: templateName, htmlFieldName: null,
additionalViewData: null);
}
public static HtmlString EditorForModel(this IHtmlHelper html, string templateName, object additionalViewData)
{
return html.Editor(expression: string.Empty, templateName: templateName, htmlFieldName: null,
additionalViewData: additionalViewData);
}
public static HtmlString EditorForModel(this IHtmlHelper html, string templateName, string htmlFieldName)
{
return html.Editor(expression: string.Empty, templateName: templateName, htmlFieldName: htmlFieldName,
additionalViewData: null);
}
public static HtmlString EditorForModel(this IHtmlHelper html, string templateName, string htmlFieldName,
object additionalViewData)
{
return html.Editor(expression: string.Empty, templateName: templateName, htmlFieldName: htmlFieldName,
additionalViewData: additionalViewData);
}
}
}

View File

@ -8,6 +8,13 @@ namespace Microsoft.AspNet.Mvc.Rendering
/// </summary>
public interface IHtmlHelper
{
/// <summary>
/// Set this property to <see cref="Mvc.Html5DateRenderingMode.Rfc3339"/> to have templated helpers such as
/// <see cref="Editor"/> and <see cref="EditorFor"/> render date and time values as RFC 3339 compliant strings.
/// By default these helpers render dates and times using the current culture.
/// </summary>
Html5DateRenderingMode Html5DateRenderingMode { get; set; }
/// <summary>
/// Gets or sets the character that replaces periods in the ID attribute of an element.
/// </summary>
@ -172,6 +179,25 @@ namespace Microsoft.AspNet.Mvc.Rendering
string optionLabel,
object htmlAttributes);
/// <summary>
/// Returns an HTML input element for each property in the object that is represented by the expression, using
/// the specified template, HTML field ID, and additional view data.
/// </summary>
/// <param name="expression">An expression that identifies the object that contains the properties to edit.
/// </param>
/// <param name="templateName">The name of the template that is used to render the object.</param>
/// <param name="htmlFieldName">
/// A string that is used to disambiguate the names of HTML input elements that are rendered for properties
/// that have the same name.
/// </param>
/// <param name="additionalViewData">
/// An anonymous object or dictionary that can contain additional view data that will be merged into the
/// <see cref="ViewDataDictionary{TModel}"/> instance that is created for the template.
/// </param>
/// <returns>The HTML markup for the input elements for each property in the object that is represented by the
/// expression.</returns>
HtmlString Editor(string expression, string templateName, string htmlFieldName, object additionalViewData);
/// <summary>
/// Converts the value of the specified object to an HTML-encoded string.
/// </summary>

View File

@ -89,6 +89,29 @@ namespace Microsoft.AspNet.Mvc.Rendering
string optionLabel,
object htmlAttributes);
/// <summary>
/// Returns an HTML input element for each property in the object that is represented by the specified
/// expression, using the specified template, an HTML field ID, and additional view data.
/// </summary>
/// <typeparam name="TValue">The type of the value.</typeparam>
/// <param name="expression">An expression that identifies the object that contains the properties to edit.
/// </param>
/// <param name="templateName">The name of the template that is used to render the object.</param>
/// <param name="htmlFieldName">
/// A string that is used to disambiguate the names of HTML input elements that are rendered for properties
/// that have the same name.
/// </param>
/// <param name="additionalViewData">
/// An anonymous object or dictionary that can contain additional view data that will be merged into the
/// <see cref="ViewDataDictionary{TModel}"/> instance that is created for the template.
/// </param>
/// <returns>The HTML markup for the input elements for each property in the object that is represented by the
/// expression.</returns>
HtmlString EditorFor<TValue>([NotNull] Expression<Func<TModel, TValue>> expression,
string templateName,
string htmlFieldName,
object additionalViewData);
/// <summary>
/// Render an input element of type "hidden".
/// </summary>