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:
parent
b3046a0285
commit
f7704ba68f
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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", })
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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" />
|
||||
|
|
|
|||
|
|
@ -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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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.
|
||||
|
|
|
|||
|
|
@ -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)
|
||||
|
|
|
|||
|
|
@ -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()
|
||||
|
|
|
|||
|
|
@ -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,
|
||||
}
|
||||
}
|
||||
|
|
@ -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);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -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>
|
||||
|
|
|
|||
|
|
@ -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>
|
||||
|
|
|
|||
Loading…
Reference in New Issue