Skip to content

Commit

Permalink
Add ModelMetadata.HtmlEncode property
Browse files Browse the repository at this point in the history
- use new `ModelMetadata.HtmlEncode` property in HTML helpers
 - conditionally in default HTML display and editor object templates (e.g.
   `@Html.DisplayFor()`) when value is non-null and the template is invoked
   with template depth greater than 1
 - unconditionally in `@Html.DisplayText()` and `@Html.DisplayTextFor()`
- test new property and its use

Also test `DisplayTextExtensions`
- unit test gap
  • Loading branch information
dougbu committed Jul 17, 2014
1 parent f9a064c commit 2b12791
Show file tree
Hide file tree
Showing 13 changed files with 555 additions and 14 deletions.
7 changes: 7 additions & 0 deletions src/System.Web.Mvc/CachedDataAnnotationsModelMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -123,6 +123,13 @@ protected override bool ComputeHideSurroundingHtml()
: base.ComputeHideSurroundingHtml();
}

protected override bool ComputeHtmlEncode()
{
return (PrototypeCache.DisplayFormat != null)
? PrototypeCache.DisplayFormat.HtmlEncode
: base.ComputeHtmlEncode();
}

protected override bool ComputeIsReadOnly()
{
if (PrototypeCache.Editable != null)
Expand Down
25 changes: 25 additions & 0 deletions src/System.Web.Mvc/CachedModelMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,7 @@ public abstract class CachedModelMetadata<TPrototypeCache> : ModelMetadata
private string _editFormatString;
private bool _hasNonDefaultEditFormat;
private bool _hideSurroundingHtml;
private bool _htmlEncode;
private bool _isReadOnly;
private bool _isRequired;
private string _nullDisplayText;
Expand All @@ -38,6 +39,7 @@ public abstract class CachedModelMetadata<TPrototypeCache> : ModelMetadata
private bool _editFormatStringComputed;
private bool _hasNonDefaultEditFormatComputed;
private bool _hideSurroundingHtmlComputed;
private bool _htmlEncodeComputed;
private bool _isReadOnlyComputed;
private bool _isRequiredComputed;
private bool _nullDisplayTextComputed;
Expand Down Expand Up @@ -207,6 +209,24 @@ public sealed override bool HideSurroundingHtml
}
}

public sealed override bool HtmlEncode
{
get
{
if (!_htmlEncodeComputed)
{
_htmlEncode = ComputeHtmlEncode();
_htmlEncodeComputed = true;
}
return _htmlEncode;
}
set
{
_htmlEncode = value;
_htmlEncodeComputed = true;
}
}

public sealed override bool IsReadOnly
{
get
Expand Down Expand Up @@ -421,6 +441,11 @@ protected virtual bool ComputeHideSurroundingHtml()
return base.HideSurroundingHtml;
}

protected virtual bool ComputeHtmlEncode()
{
return base.HtmlEncode;
}

protected virtual bool ComputeIsReadOnly()
{
return base.IsReadOnly;
Expand Down
1 change: 1 addition & 0 deletions src/System.Web.Mvc/DataAnnotationsModelMetadataProvider.cs
Original file line number Diff line number Diff line change
Expand Up @@ -121,6 +121,7 @@ private static void SetFromDataTypeAndDisplayAttributes(DataAnnotationsModelMeta
result.NullDisplayText = displayFormatAttribute.NullDisplayText;
result.DisplayFormatString = displayFormatAttribute.DataFormatString;
result.ConvertEmptyStringToNull = displayFormatAttribute.ConvertEmptyStringToNull;
result.HtmlEncode = displayFormatAttribute.HtmlEncode;

if (displayFormatAttribute.ApplyFormatInEditMode)
{
Expand Down
8 changes: 7 additions & 1 deletion src/System.Web.Mvc/Html/DefaultDisplayTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -174,7 +174,13 @@ internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateH
if (templateInfo.TemplateDepth > 1)
{
// DDB #224751
return modelMetadata.SimpleDisplayText;
string text = modelMetadata.SimpleDisplayText;
if (modelMetadata.HtmlEncode)
{
text = html.Encode(text);
}

return text;
}

foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
Expand Down
13 changes: 12 additions & 1 deletion src/System.Web.Mvc/Html/DefaultEditorTemplates.cs
Original file line number Diff line number Diff line change
Expand Up @@ -230,8 +230,19 @@ internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateH

if (templateInfo.TemplateDepth > 1)
{
if (modelMetadata.Model == null)
{
return modelMetadata.NullDisplayText;
}

// DDB #224751
return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
string text = modelMetadata.SimpleDisplayText;
if (modelMetadata.HtmlEncode)
{
text = html.Encode(text);
}

return text;
}

foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
Expand Down
14 changes: 10 additions & 4 deletions src/System.Web.Mvc/Html/DisplayTextExtensions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -9,18 +9,24 @@ public static class DisplayTextExtensions
{
public static MvcHtmlString DisplayText(this HtmlHelper html, string name)
{
return DisplayTextHelper(ModelMetadata.FromStringExpression(name, html.ViewContext.ViewData));
return DisplayTextHelper(html, ModelMetadata.FromStringExpression(name, html.ViewContext.ViewData));
}

[SuppressMessage("Microsoft.Design", "CA1006:DoNotNestGenericTypesInMemberSignatures", Justification = "This is an appropriate nesting of generic types")]
public static MvcHtmlString DisplayTextFor<TModel, TResult>(this HtmlHelper<TModel> html, Expression<Func<TModel, TResult>> expression)
{
return DisplayTextHelper(ModelMetadata.FromLambdaExpression(expression, html.ViewData));
return DisplayTextHelper(html, ModelMetadata.FromLambdaExpression(expression, html.ViewData));
}

private static MvcHtmlString DisplayTextHelper(ModelMetadata metadata)
private static MvcHtmlString DisplayTextHelper(HtmlHelper html, ModelMetadata metadata)
{
return MvcHtmlString.Create(metadata.SimpleDisplayText);
string text = metadata.SimpleDisplayText;
if (metadata.HtmlEncode)
{
text = html.Encode(text);
}

return MvcHtmlString.Create(text);
}
}
}
7 changes: 7 additions & 0 deletions src/System.Web.Mvc/ModelMetadata.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,6 +28,7 @@ public class ModelMetadata
/// </summary>
private Dictionary<string, object> _additionalValues = new Dictionary<string, object>(StringComparer.OrdinalIgnoreCase);
private bool _convertEmptyStringToNull = true;
private bool _htmlEncode = true;
private bool _isRequired;
private object _model;
private Func<object> _modelAccessor;
Expand Down Expand Up @@ -96,6 +97,12 @@ public virtual bool ConvertEmptyStringToNull

public virtual bool HideSurroundingHtml { get; set; }

public virtual bool HtmlEncode
{
get { return _htmlEncode; }
set { _htmlEncode = value; }
}

public virtual bool IsComplexType
{
get { return !(TypeDescriptor.GetConverter(ModelType).CanConvertFrom(typeof(string))); }
Expand Down
14 changes: 10 additions & 4 deletions test/System.Web.Mvc.Test/Html/Test/DefaultDisplayTemplatesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -454,14 +454,20 @@ public void ObjectTemplateDisplaysNullDisplayTextWhenObjectIsNull()
Assert.Equal(metadata.NullDisplayText, result);
}

[Fact]
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne()
[Theory]
[PropertyData("DisplayTextData", PropertyType = typeof(DisplayTextExtensionsTest))]
public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanOne(
string simpleDisplayText,
bool htmlEncode,
string expectedResult)
{
// Arrange
ObjectTemplateModel model = new ObjectTemplateModel();
HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(ObjectTemplateModel));
metadata.SimpleDisplayText = "Simple Display Text";
metadata.SimpleDisplayText = simpleDisplayText;
metadata.HtmlEncode = htmlEncode;

html.ViewData.ModelMetadata = metadata;
html.ViewData.TemplateInfo.VisitedObjects.Add("foo");
html.ViewData.TemplateInfo.VisitedObjects.Add("bar");
Expand All @@ -470,7 +476,7 @@ public void ObjectTemplateDisplaysSimpleDisplayTextWhenTemplateDepthGreaterThanO
string result = DefaultDisplayTemplates.ObjectTemplate(html, SpyCallback);

// Assert
Assert.Equal(metadata.SimpleDisplayText, result);
Assert.Equal(expectedResult, result);
}

[Fact]
Expand Down
14 changes: 10 additions & 4 deletions test/System.Web.Mvc.Test/Html/Test/DefaultEditorTemplatesTest.cs
Original file line number Diff line number Diff line change
Expand Up @@ -697,24 +697,30 @@ public void ObjectTemplateDisplaysNullDisplayTextWithNullModelAndTemplateDepthGr
Assert.Equal(metadata.NullDisplayText, result);
}

[Fact]
public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne()
[Theory]
[PropertyData("DisplayTextData", PropertyType = typeof(DisplayTextExtensionsTest))]
public void ObjectTemplateDisplaysSimpleDisplayTextWithNonNullModelTemplateDepthGreaterThanOne(
string simpleDisplayText,
bool htmlEncode,
string expectedResult)
{
// Arrange
ObjectTemplateModel model = new ObjectTemplateModel();
HtmlHelper html = MakeHtmlHelper<ObjectTemplateModel>(model);
ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => model, typeof(ObjectTemplateModel));
html.ViewData.ModelMetadata = metadata;
metadata.NullDisplayText = "Null Display Text";
metadata.SimpleDisplayText = "Simple Display Text";
metadata.SimpleDisplayText = simpleDisplayText;
metadata.HtmlEncode = htmlEncode;

html.ViewData.TemplateInfo.VisitedObjects.Add("foo");
html.ViewData.TemplateInfo.VisitedObjects.Add("bar");

// Act
string result = DefaultEditorTemplates.ObjectTemplate(html, SpyCallback);

// Assert
Assert.Equal(metadata.SimpleDisplayText, result);
Assert.Equal(expectedResult, result);
}

// PasswordTemplate
Expand Down
Loading

0 comments on commit 2b12791

Please sign in to comment.