1 // Copyright (c) Microsoft Corporation. All rights reserved. See License.txt in the project root for license information.
2 
3 using System.Collections;
4 using System.Collections.Generic;
5 using System.Data;
6 using System.Globalization;
7 using System.Linq;
8 using System.Text;
9 using System.Web.Mvc.Properties;
10 using System.Web.UI.WebControls;
11 
12 namespace System.Web.Mvc.Html
13 {
14     internal static class DefaultDisplayTemplates
15     {
BooleanTemplate(HtmlHelper html)16         internal static string BooleanTemplate(HtmlHelper html)
17         {
18             bool? value = null;
19             if (html.ViewContext.ViewData.Model != null)
20             {
21                 value = Convert.ToBoolean(html.ViewContext.ViewData.Model, CultureInfo.InvariantCulture);
22             }
23 
24             return html.ViewContext.ViewData.ModelMetadata.IsNullableValueType
25                        ? BooleanTemplateDropDownList(value)
26                        : BooleanTemplateCheckbox(value ?? false);
27         }
28 
BooleanTemplateCheckbox(bool value)29         private static string BooleanTemplateCheckbox(bool value)
30         {
31             TagBuilder inputTag = new TagBuilder("input");
32             inputTag.AddCssClass("check-box");
33             inputTag.Attributes["disabled"] = "disabled";
34             inputTag.Attributes["type"] = "checkbox";
35             if (value)
36             {
37                 inputTag.Attributes["checked"] = "checked";
38             }
39 
40             return inputTag.ToString(TagRenderMode.SelfClosing);
41         }
42 
43         private static string BooleanTemplateDropDownList(bool? value)
44         {
45             StringBuilder builder = new StringBuilder();
46 
47             TagBuilder selectTag = new TagBuilder("select");
48             selectTag.AddCssClass("list-box");
49             selectTag.AddCssClass("tri-state");
50             selectTag.Attributes["disabled"] = "disabled";
51             builder.Append(selectTag.ToString(TagRenderMode.StartTag));
52 
53             foreach (SelectListItem item in DefaultEditorTemplates.TriStateValues(value))
54             {
55                 builder.Append(SelectExtensions.ListItemToOption(item));
56             }
57 
58             builder.Append(selectTag.ToString(TagRenderMode.EndTag));
59             return builder.ToString();
60         }
61 
CollectionTemplate(HtmlHelper html)62         internal static string CollectionTemplate(HtmlHelper html)
63         {
64             return CollectionTemplate(html, TemplateHelpers.TemplateHelper);
65         }
66 
CollectionTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper)67         internal static string CollectionTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper)
68         {
69             object model = html.ViewContext.ViewData.ModelMetadata.Model;
70             if (model == null)
71             {
72                 return String.Empty;
73             }
74 
75             IEnumerable collection = model as IEnumerable;
76             if (collection == null)
77             {
78                 throw new InvalidOperationException(
79                     String.Format(
80                         CultureInfo.CurrentCulture,
81                         MvcResources.Templates_TypeMustImplementIEnumerable,
82                         model.GetType().FullName));
83             }
84 
85             Type typeInCollection = typeof(string);
86             Type genericEnumerableType = TypeHelpers.ExtractGenericInterface(collection.GetType(), typeof(IEnumerable<>));
87             if (genericEnumerableType != null)
88             {
89                 typeInCollection = genericEnumerableType.GetGenericArguments()[0];
90             }
91             bool typeInCollectionIsNullableValueType = TypeHelpers.IsNullableValueType(typeInCollection);
92 
93             string oldPrefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
94 
95             try
96             {
97                 html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = String.Empty;
98 
99                 string fieldNameBase = oldPrefix;
100                 StringBuilder result = new StringBuilder();
101                 int index = 0;
102 
103                 foreach (object item in collection)
104                 {
105                     Type itemType = typeInCollection;
106                     if (item != null && !typeInCollectionIsNullableValueType)
107                     {
108                         itemType = item.GetType();
109                     }
110                     ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => item, itemType);
111                     string fieldName = String.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++);
112                     string output = templateHelper(html, metadata, fieldName, null /* templateName */, DataBoundControlMode.ReadOnly, null /* additionalViewData */);
113                     result.Append(output);
114                 }
115 
116                 return result.ToString();
117             }
118             finally
119             {
120                 html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = oldPrefix;
121             }
122         }
123 
DecimalTemplate(HtmlHelper html)124         internal static string DecimalTemplate(HtmlHelper html)
125         {
126             if (html.ViewContext.ViewData.TemplateInfo.FormattedModelValue == html.ViewContext.ViewData.ModelMetadata.Model)
127             {
128                 html.ViewContext.ViewData.TemplateInfo.FormattedModelValue = String.Format(CultureInfo.CurrentCulture, "{0:0.00}", html.ViewContext.ViewData.ModelMetadata.Model);
129             }
130 
131             return StringTemplate(html);
132         }
133 
EmailAddressTemplate(HtmlHelper html)134         internal static string EmailAddressTemplate(HtmlHelper html)
135         {
136             return String.Format(CultureInfo.InvariantCulture,
137                                  "<a href=\"mailto:{0}\">{1}</a>",
138                                  html.AttributeEncode(html.ViewContext.ViewData.Model),
139                                  html.Encode(html.ViewContext.ViewData.TemplateInfo.FormattedModelValue));
140         }
141 
HiddenInputTemplate(HtmlHelper html)142         internal static string HiddenInputTemplate(HtmlHelper html)
143         {
144             if (html.ViewContext.ViewData.ModelMetadata.HideSurroundingHtml)
145             {
146                 return String.Empty;
147             }
148             return StringTemplate(html);
149         }
150 
HtmlTemplate(HtmlHelper html)151         internal static string HtmlTemplate(HtmlHelper html)
152         {
153             return html.ViewContext.ViewData.TemplateInfo.FormattedModelValue.ToString();
154         }
155 
ObjectTemplate(HtmlHelper html)156         internal static string ObjectTemplate(HtmlHelper html)
157         {
158             return ObjectTemplate(html, TemplateHelpers.TemplateHelper);
159         }
160 
ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper)161         internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper)
162         {
163             ViewDataDictionary viewData = html.ViewContext.ViewData;
164             TemplateInfo templateInfo = viewData.TemplateInfo;
165             ModelMetadata modelMetadata = viewData.ModelMetadata;
166             StringBuilder builder = new StringBuilder();
167 
168             if (modelMetadata.Model == null)
169             {
170                 // DDB #225237
171                 return modelMetadata.NullDisplayText;
172             }
173 
174             if (templateInfo.TemplateDepth > 1)
175             {
176                 // DDB #224751
177                 return modelMetadata.SimpleDisplayText;
178             }
179 
180             foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo)))
181             {
182                 if (!propertyMetadata.HideSurroundingHtml)
183                 {
184                     string label = propertyMetadata.GetDisplayName();
185                     if (!String.IsNullOrEmpty(label))
186                     {
187                         builder.AppendFormat(CultureInfo.InvariantCulture, "<div class=\"display-label\">{0}</div>", label);
188                         builder.AppendLine();
189                     }
190 
191                     builder.Append("<div class=\"display-field\">");
192                 }
193 
194                 builder.Append(templateHelper(html, propertyMetadata, propertyMetadata.PropertyName, null /* templateName */, DataBoundControlMode.ReadOnly, null /* additionalViewData */));
195 
196                 if (!propertyMetadata.HideSurroundingHtml)
197                 {
198                     builder.AppendLine("</div>");
199                 }
200             }
201 
202             return builder.ToString();
203         }
204 
ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)205         private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo)
206         {
207             return
208                 metadata.ShowForDisplay
209                 && metadata.ModelType != typeof(EntityState)
210                 && !metadata.IsComplexType
211                 && !templateInfo.Visited(metadata);
212         }
213 
StringTemplate(HtmlHelper html)214         internal static string StringTemplate(HtmlHelper html)
215         {
216             return html.Encode(html.ViewContext.ViewData.TemplateInfo.FormattedModelValue);
217         }
218 
UrlTemplate(HtmlHelper html)219         internal static string UrlTemplate(HtmlHelper html)
220         {
221             return String.Format(CultureInfo.InvariantCulture,
222                                  "<a href=\"{0}\">{1}</a>",
223                                  html.AttributeEncode(html.ViewContext.ViewData.Model),
224                                  html.Encode(html.ViewContext.ViewData.TemplateInfo.FormattedModelValue));
225         }
226     }
227 }
228