MVC3 integrated, with some changes to make it compile on Mono and with Razor2
[mono.git] / mcs / class / System.Web.Mvc3 / Mvc / Html / DefaultEditorTemplates.cs
1 namespace System.Web.Mvc.Html {
2     using System;
3     using System.Collections;
4     using System.Collections.Generic;
5     using System.Data;
6     using System.Data.Linq;
7     using System.Globalization;
8     using System.Linq;
9     using System.Text;
10     using System.Web.Mvc.Resources;
11     using System.Web.UI.WebControls;
12
13     internal static class DefaultEditorTemplates {
14         internal static string BooleanTemplate(HtmlHelper html) {
15             bool? value = null;
16             if (html.ViewContext.ViewData.Model != null) {
17                 value = Convert.ToBoolean(html.ViewContext.ViewData.Model, CultureInfo.InvariantCulture);
18             }
19
20             return html.ViewContext.ViewData.ModelMetadata.IsNullableValueType
21                         ? BooleanTemplateDropDownList(html, value)
22                         : BooleanTemplateCheckbox(html, value ?? false);
23         }
24
25         private static string BooleanTemplateCheckbox(HtmlHelper html, bool value) {
26             return html.CheckBox(String.Empty, value, CreateHtmlAttributes("check-box")).ToHtmlString();
27         }
28
29         private static string BooleanTemplateDropDownList(HtmlHelper html, bool? value) {
30             return html.DropDownList(String.Empty, TriStateValues(value), CreateHtmlAttributes("list-box tri-state")).ToHtmlString();
31
32         }
33
34         internal static string CollectionTemplate(HtmlHelper html) {
35             return CollectionTemplate(html, TemplateHelpers.TemplateHelper);
36         }
37
38         internal static string CollectionTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper) {
39             object model = html.ViewContext.ViewData.ModelMetadata.Model;
40             if (model == null) {
41                 return String.Empty;
42             }
43
44             IEnumerable collection = model as IEnumerable;
45             if (collection == null) {
46                 throw new InvalidOperationException(
47                     String.Format(
48                         CultureInfo.CurrentCulture,
49                         MvcResources.Templates_TypeMustImplementIEnumerable,
50                         model.GetType().FullName
51                     )
52                 );
53             }
54
55             Type typeInCollection = typeof(string);
56             Type genericEnumerableType = TypeHelpers.ExtractGenericInterface(collection.GetType(), typeof(IEnumerable<>));
57             if (genericEnumerableType != null) {
58                 typeInCollection = genericEnumerableType.GetGenericArguments()[0];
59             }
60             bool typeInCollectionIsNullableValueType = TypeHelpers.IsNullableValueType(typeInCollection);
61
62             string oldPrefix = html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix;
63
64             try {
65                 html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = String.Empty;
66
67                 string fieldNameBase = oldPrefix;
68                 StringBuilder result = new StringBuilder();
69                 int index = 0;
70
71                 foreach (object item in collection) {
72                     Type itemType = typeInCollection;
73                     if (item != null && !typeInCollectionIsNullableValueType) {
74                         itemType = item.GetType();
75                     }
76                     ModelMetadata metadata = ModelMetadataProviders.Current.GetMetadataForType(() => item, itemType);
77                     string fieldName = String.Format(CultureInfo.InvariantCulture, "{0}[{1}]", fieldNameBase, index++);
78                     string output = templateHelper(html, metadata, fieldName, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */);
79                     result.Append(output);
80                 }
81
82                 return result.ToString();
83             }
84             finally {
85                 html.ViewContext.ViewData.TemplateInfo.HtmlFieldPrefix = oldPrefix;
86             }
87         }
88
89         internal static string DecimalTemplate(HtmlHelper html) {
90             if (html.ViewContext.ViewData.TemplateInfo.FormattedModelValue == html.ViewContext.ViewData.ModelMetadata.Model) {
91                 html.ViewContext.ViewData.TemplateInfo.FormattedModelValue = String.Format(CultureInfo.CurrentCulture, "{0:0.00}", html.ViewContext.ViewData.ModelMetadata.Model);
92             }
93
94             return StringTemplate(html);
95         }
96
97         internal static string HiddenInputTemplate(HtmlHelper html) {
98             string result;
99
100             if (html.ViewContext.ViewData.ModelMetadata.HideSurroundingHtml) {
101                 result = String.Empty;
102             }
103             else {
104                 result = DefaultDisplayTemplates.StringTemplate(html);
105             }
106
107             object model = html.ViewContext.ViewData.Model;
108
109             Binary modelAsBinary = model as Binary;
110             if (modelAsBinary != null) {
111                 model = Convert.ToBase64String(modelAsBinary.ToArray());
112             }
113             else {
114                 byte[] modelAsByteArray = model as byte[];
115                 if (modelAsByteArray != null) {
116                     model = Convert.ToBase64String(modelAsByteArray);
117                 }
118             }
119
120             result += html.Hidden(String.Empty, model).ToHtmlString();
121             return result;
122         }
123
124         internal static string MultilineTextTemplate(HtmlHelper html) {
125             return html.TextArea(String.Empty,
126                                  html.ViewContext.ViewData.TemplateInfo.FormattedModelValue.ToString(),
127                                  0 /* rows */, 0 /* columns */,
128                                  CreateHtmlAttributes("text-box multi-line")).ToHtmlString();
129         }
130
131         private static IDictionary<string, object> CreateHtmlAttributes(string className) {
132             return new Dictionary<string, object>() {
133                 { "class", className }
134             };
135         }
136
137         internal static string ObjectTemplate(HtmlHelper html) {
138             return ObjectTemplate(html, TemplateHelpers.TemplateHelper);
139         }
140
141         internal static string ObjectTemplate(HtmlHelper html, TemplateHelpers.TemplateHelperDelegate templateHelper) {
142             ViewDataDictionary viewData = html.ViewContext.ViewData;
143             TemplateInfo templateInfo = viewData.TemplateInfo;
144             ModelMetadata modelMetadata = viewData.ModelMetadata;
145             StringBuilder builder = new StringBuilder();
146
147             if (templateInfo.TemplateDepth > 1) {    // DDB #224751
148                 return modelMetadata.Model == null ? modelMetadata.NullDisplayText : modelMetadata.SimpleDisplayText;
149             }
150
151             foreach (ModelMetadata propertyMetadata in modelMetadata.Properties.Where(pm => ShouldShow(pm, templateInfo))) {
152                 if (!propertyMetadata.HideSurroundingHtml) {
153                     string label = LabelExtensions.LabelHelper(html, propertyMetadata, propertyMetadata.PropertyName).ToHtmlString();
154                     if (!String.IsNullOrEmpty(label)) {
155                         builder.AppendFormat(CultureInfo.InvariantCulture, "<div class=\"editor-label\">{0}</div>\r\n", label);
156                     }
157
158                     builder.Append("<div class=\"editor-field\">");
159                 }
160
161                 builder.Append(templateHelper(html, propertyMetadata, propertyMetadata.PropertyName, null /* templateName */, DataBoundControlMode.Edit, null /* additionalViewData */));
162
163                 if (!propertyMetadata.HideSurroundingHtml) {
164                     builder.Append(" ");
165                     builder.Append(html.ValidationMessage(propertyMetadata.PropertyName));
166                     builder.Append("</div>\r\n");
167                 }
168             }
169
170             return builder.ToString();
171         }
172
173         internal static string PasswordTemplate(HtmlHelper html) {
174             return html.Password(String.Empty,
175                                  html.ViewContext.ViewData.TemplateInfo.FormattedModelValue,
176                                  CreateHtmlAttributes("text-box single-line password")).ToHtmlString();
177         }
178
179         private static bool ShouldShow(ModelMetadata metadata, TemplateInfo templateInfo) {
180             return
181                 metadata.ShowForEdit
182 #if !MONO
183                 && metadata.ModelType != typeof(EntityState)
184 #endif
185                 && !metadata.IsComplexType
186                 && !templateInfo.Visited(metadata);
187         }
188
189         internal static string StringTemplate(HtmlHelper html) {
190             return html.TextBox(String.Empty,
191                                 html.ViewContext.ViewData.TemplateInfo.FormattedModelValue,
192                                 CreateHtmlAttributes("text-box single-line")).ToHtmlString();
193         }
194
195         internal static List<SelectListItem> TriStateValues(bool? value) {
196             return new List<SelectListItem> {
197                 new SelectListItem { Text = MvcResources.Common_TriState_NotSet, Value = String.Empty, Selected = !value.HasValue },
198                 new SelectListItem { Text = MvcResources.Common_TriState_True, Value = "true", Selected = value.HasValue && value.Value },
199                 new SelectListItem { Text = MvcResources.Common_TriState_False, Value = "false", Selected = value.HasValue && !value.Value },
200             };
201         }
202     }
203 }