Fix bugs in sizing TableLayoutPanel (Xamarin bug 18638)
[mono.git] / mcs / class / System.Web.Mvc2 / System.Web.Mvc / HtmlHelper.cs
1 /* ****************************************************************************\r
2  *\r
3  * Copyright (c) Microsoft Corporation. All rights reserved.\r
4  *\r
5  * This software is subject to the Microsoft Public License (Ms-PL). \r
6  * A copy of the license can be found in the license.htm file included \r
7  * in this distribution.\r
8  *\r
9  * You must not remove this notice, or any other, from this software.\r
10  *\r
11  * ***************************************************************************/\r
12 \r
13 namespace System.Web.Mvc {\r
14     using System;\r
15     using System.Collections.Generic;\r
16     using System.Diagnostics.CodeAnalysis;\r
17     using System.Globalization;\r
18     using System.IO;\r
19     using System.Text;\r
20     using System.Web;\r
21     using System.Web.Mvc.Resources;\r
22     using System.Web.Routing;\r
23 \r
24     [SuppressMessage("Microsoft.Security", "CA2112:SecuredTypesShouldNotExposeFields",\r
25         Justification = "Public fields for CSS names do not contain secure information.")]\r
26     public class HtmlHelper {\r
27 \r
28         private delegate string HtmlEncoder(object value);\r
29         private static readonly HtmlEncoder _htmlEncoder = GetHtmlEncoder();\r
30 \r
31         private static string _idAttributeDotReplacement;\r
32 \r
33         public static readonly string ValidationInputCssClassName = "input-validation-error";\r
34         public static readonly string ValidationInputValidCssClassName = "input-validation-valid";\r
35         public static readonly string ValidationMessageCssClassName = "field-validation-error";\r
36         public static readonly string ValidationMessageValidCssClassName = "field-validation-valid";\r
37         public static readonly string ValidationSummaryCssClassName = "validation-summary-errors";\r
38         public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid";\r
39 \r
40         private AntiForgeryDataSerializer _serializer;\r
41 \r
42         public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer)\r
43             : this(viewContext, viewDataContainer, RouteTable.Routes) {\r
44         }\r
45 \r
46         public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection) {\r
47             if (viewContext == null) {\r
48                 throw new ArgumentNullException("viewContext");\r
49             }\r
50             if (viewDataContainer == null) {\r
51                 throw new ArgumentNullException("viewDataContainer");\r
52             }\r
53             if (routeCollection == null) {\r
54                 throw new ArgumentNullException("routeCollection");\r
55             }\r
56             ViewContext = viewContext;\r
57             ViewDataContainer = viewDataContainer;\r
58             RouteCollection = routeCollection;\r
59         }\r
60 \r
61         public static string IdAttributeDotReplacement {\r
62             get {\r
63                 if (String.IsNullOrEmpty(_idAttributeDotReplacement)) {\r
64                     _idAttributeDotReplacement = "_";\r
65                 }\r
66                 return _idAttributeDotReplacement;\r
67             }\r
68             set {\r
69                 _idAttributeDotReplacement = value;\r
70             }\r
71         }\r
72 \r
73         public RouteCollection RouteCollection {\r
74             get;\r
75             private set;\r
76         }\r
77 \r
78         internal AntiForgeryDataSerializer Serializer {\r
79             get {\r
80                 if (_serializer == null) {\r
81                     _serializer = new AntiForgeryDataSerializer();\r
82                 }\r
83                 return _serializer;\r
84             }\r
85             set {\r
86                 _serializer = value;\r
87             }\r
88         }\r
89 \r
90         public ViewContext ViewContext {\r
91             get;\r
92             private set;\r
93         }\r
94 \r
95         public ViewDataDictionary ViewData {\r
96             get {\r
97                 return ViewDataContainer.ViewData;\r
98             }\r
99         }\r
100 \r
101         public IViewDataContainer ViewDataContainer {\r
102             get;\r
103             private set;\r
104         }\r
105 \r
106         public MvcHtmlString AntiForgeryToken() {\r
107             return AntiForgeryToken(null /* salt */);\r
108         }\r
109 \r
110         public MvcHtmlString AntiForgeryToken(string salt) {\r
111             return AntiForgeryToken(salt, null /* domain */, null /* path */);\r
112         }\r
113 \r
114         public MvcHtmlString AntiForgeryToken(string salt, string domain, string path) {\r
115             string formValue = GetAntiForgeryTokenAndSetCookie(salt, domain, path);\r
116             string fieldName = AntiForgeryData.GetAntiForgeryTokenName(null);\r
117 \r
118             TagBuilder builder = new TagBuilder("input");\r
119             builder.Attributes["type"] = "hidden";\r
120             builder.Attributes["name"] = fieldName;\r
121             builder.Attributes["value"] = formValue;\r
122             return builder.ToMvcHtmlString(TagRenderMode.SelfClosing);\r
123         }\r
124 \r
125         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",\r
126             Justification = "For consistency, all helpers are instance methods.")]\r
127         public string AttributeEncode(string value) {\r
128             return (!String.IsNullOrEmpty(value)) ? HttpUtility.HtmlAttributeEncode(value) : String.Empty;\r
129         }\r
130 \r
131         public string AttributeEncode(object value) {\r
132             return AttributeEncode(Convert.ToString(value, CultureInfo.InvariantCulture));\r
133         }\r
134 \r
135         public void EnableClientValidation() {\r
136             ViewContext.ClientValidationEnabled = true;\r
137         }\r
138 \r
139         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",\r
140             Justification = "For consistency, all helpers are instance methods.")]\r
141         public string Encode(string value) {\r
142             return (!String.IsNullOrEmpty(value)) ? HttpUtility.HtmlEncode(value) : String.Empty;\r
143         }\r
144 \r
145         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",\r
146             Justification = "For consistency, all helpers are instance methods.")]\r
147         public string Encode(object value) {\r
148             return _htmlEncoder(value);\r
149         }\r
150 \r
151         // method used if HttpUtility.HtmlEncode(object) method does not exist\r
152         private static string EncodeLegacy(object value) {\r
153             string stringVal = Convert.ToString(value, CultureInfo.CurrentCulture);\r
154             return (!String.IsNullOrEmpty(stringVal)) ? HttpUtility.HtmlEncode(stringVal) : String.Empty;\r
155         }\r
156 \r
157         internal string EvalString(string key) {\r
158             return Convert.ToString(ViewData.Eval(key), CultureInfo.CurrentCulture);\r
159         }\r
160 \r
161         internal bool EvalBoolean(string key) {\r
162             return Convert.ToBoolean(ViewData.Eval(key), CultureInfo.InvariantCulture);\r
163         }\r
164 \r
165         internal static IView FindPartialView(ViewContext viewContext, string partialViewName, ViewEngineCollection viewEngineCollection) {\r
166             ViewEngineResult result = viewEngineCollection.FindPartialView(viewContext, partialViewName);\r
167             if (result.View != null) {\r
168                 return result.View;\r
169             }\r
170 \r
171             StringBuilder locationsText = new StringBuilder();\r
172             foreach (string location in result.SearchedLocations) {\r
173                 locationsText.AppendLine();\r
174                 locationsText.Append(location);\r
175             }\r
176 \r
177             throw new InvalidOperationException(String.Format(CultureInfo.CurrentUICulture,\r
178                 MvcResources.Common_PartialViewNotFound, partialViewName, locationsText));\r
179         }\r
180 \r
181         public static string GenerateIdFromName(string name) {\r
182             return GenerateIdFromName(name, IdAttributeDotReplacement);\r
183         }\r
184 \r
185         public static string GenerateIdFromName(string name, string idAttributeDotReplacement) {\r
186             if (name == null) {\r
187                 throw new ArgumentNullException("name");\r
188             }\r
189             if (idAttributeDotReplacement == null) {\r
190                 throw new ArgumentNullException("idAttributeDotReplacement");\r
191             }\r
192 \r
193             return name.Replace(".", idAttributeDotReplacement);\r
194         }\r
195 \r
196         public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {\r
197             return GenerateLink(requestContext, routeCollection, linkText, routeName, actionName, controllerName, null/* protocol */, null/* hostName */, null/* fragment */, routeValues, htmlAttributes);\r
198         }\r
199 \r
200         public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {\r
201             return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, true /* includeImplicitMvcValues */);\r
202         }\r
203 \r
204         private static string GenerateLinkInternal(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes, bool includeImplicitMvcValues) {\r
205             string url = UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, routeCollection, requestContext, includeImplicitMvcValues);\r
206             TagBuilder tagBuilder = new TagBuilder("a") {\r
207                 InnerHtml = (!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : String.Empty\r
208             };\r
209             tagBuilder.MergeAttributes(htmlAttributes);\r
210             tagBuilder.MergeAttribute("href", url);\r
211             return tagBuilder.ToString(TagRenderMode.Normal);\r
212         }\r
213 \r
214         public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {\r
215             return GenerateRouteLink(requestContext, routeCollection, linkText, routeName, null/* protocol */, null/* hostName */, null/* fragment */, routeValues, htmlAttributes);\r
216         }\r
217 \r
218         public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) {\r
219             return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, null /* actionName */, null /* controllerName */, protocol, hostName, fragment, routeValues, htmlAttributes, false /* includeImplicitMvcValues */);\r
220         }\r
221 \r
222         private string GetAntiForgeryTokenAndSetCookie(string salt, string domain, string path) {\r
223             string cookieName = AntiForgeryData.GetAntiForgeryTokenName(ViewContext.HttpContext.Request.ApplicationPath);\r
224 \r
225             AntiForgeryData cookieToken;\r
226             HttpCookie cookie = ViewContext.HttpContext.Request.Cookies[cookieName];\r
227             if (cookie != null) {\r
228                 cookieToken = Serializer.Deserialize(cookie.Value);\r
229             }\r
230             else {\r
231                 cookieToken = AntiForgeryData.NewToken();\r
232                 string cookieValue = Serializer.Serialize(cookieToken);\r
233 \r
234                 HttpCookie newCookie = new HttpCookie(cookieName, cookieValue) { HttpOnly = true, Domain = domain };\r
235                 if (!String.IsNullOrEmpty(path)) {\r
236                     newCookie.Path = path;\r
237                 }\r
238                 ViewContext.HttpContext.Response.Cookies.Set(newCookie);\r
239             }\r
240 \r
241             AntiForgeryData formToken = new AntiForgeryData(cookieToken) {\r
242                 Salt = salt,\r
243                 Username = AntiForgeryData.GetUsername(ViewContext.HttpContext.User)\r
244             };\r
245             string formValue = Serializer.Serialize(formToken);\r
246             return formValue;\r
247         }\r
248 \r
249         public static string GetFormMethodString(FormMethod method) {\r
250             switch (method) {\r
251                 case FormMethod.Get:\r
252                     return "get";\r
253                 case FormMethod.Post:\r
254                     return "post";\r
255                 default:\r
256                     return "post";\r
257             }\r
258         }\r
259 \r
260         // selects the v3.5 (legacy) or v4 HTML encoder\r
261         private static HtmlEncoder GetHtmlEncoder() {\r
262             return TypeHelpers.CreateDelegate<HtmlEncoder>(TypeHelpers.SystemWebAssembly, "System.Web.HttpUtility", "HtmlEncode", null)\r
263                 ?? EncodeLegacy;\r
264         }\r
265 \r
266         public static string GetInputTypeString(InputType inputType) {\r
267             switch (inputType) {\r
268                 case InputType.CheckBox:\r
269                     return "checkbox";\r
270                 case InputType.Hidden:\r
271                     return "hidden";\r
272                 case InputType.Password:\r
273                     return "password";\r
274                 case InputType.Radio:\r
275                     return "radio";\r
276                 case InputType.Text:\r
277                     return "text";\r
278                 default:\r
279                     return "text";\r
280             }\r
281         }\r
282 \r
283         internal object GetModelStateValue(string key, Type destinationType) {\r
284             ModelState modelState;\r
285             if (ViewData.ModelState.TryGetValue(key, out modelState)) {\r
286                 if (modelState.Value != null) {\r
287                     return modelState.Value.ConvertTo(destinationType, null /* culture */);\r
288                 }\r
289             }\r
290             return null;\r
291         }\r
292 \r
293         public MvcHtmlString HttpMethodOverride(HttpVerbs httpVerb) {\r
294             string httpMethod;\r
295             switch (httpVerb) {\r
296                 case HttpVerbs.Delete:\r
297                     httpMethod = "DELETE";\r
298                     break;\r
299                 case HttpVerbs.Head:\r
300                     httpMethod = "HEAD";\r
301                     break;\r
302                 case HttpVerbs.Put:\r
303                     httpMethod = "PUT";\r
304                     break;\r
305                 default:\r
306                     throw new ArgumentException(MvcResources.HtmlHelper_InvalidHttpVerb, "httpVerb");\r
307             }\r
308 \r
309             return HttpMethodOverride(httpMethod);\r
310         }\r
311 \r
312         [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic",\r
313             Justification = "For consistency, all helpers are instance methods.")]\r
314         public MvcHtmlString HttpMethodOverride(string httpMethod) {\r
315             if (String.IsNullOrEmpty(httpMethod)) {\r
316                 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "httpMethod");\r
317             }\r
318             if (String.Equals(httpMethod, "GET", StringComparison.OrdinalIgnoreCase) ||\r
319                 String.Equals(httpMethod, "POST", StringComparison.OrdinalIgnoreCase)) {\r
320                 throw new ArgumentException(MvcResources.HtmlHelper_InvalidHttpMethod, "httpMethod");\r
321             }\r
322 \r
323             TagBuilder tagBuilder = new TagBuilder("input");\r
324             tagBuilder.Attributes["type"] = "hidden";\r
325             tagBuilder.Attributes["name"] = HttpRequestExtensions.XHttpMethodOverrideKey;\r
326             tagBuilder.Attributes["value"] = httpMethod;\r
327 \r
328             return tagBuilder.ToMvcHtmlString(TagRenderMode.SelfClosing);\r
329         }\r
330 \r
331         internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, TextWriter writer, ViewEngineCollection viewEngineCollection) {\r
332             if (String.IsNullOrEmpty(partialViewName)) {\r
333                 throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName");\r
334             }\r
335 \r
336             ViewDataDictionary newViewData = null;\r
337 \r
338             if (model == null) {\r
339                 if (viewData == null) {\r
340                     newViewData = new ViewDataDictionary(ViewData);\r
341                 }\r
342                 else {\r
343                     newViewData = new ViewDataDictionary(viewData);\r
344                 }\r
345             }\r
346             else {\r
347                 if (viewData == null) {\r
348                     newViewData = new ViewDataDictionary(model);\r
349                 }\r
350                 else {\r
351                     newViewData = new ViewDataDictionary(viewData) { Model = model };\r
352                 }\r
353             }\r
354 \r
355             ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View, newViewData, ViewContext.TempData, writer);\r
356             IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection);\r
357             view.Render(newViewContext, writer);\r
358         }\r
359 \r
360     }\r
361 }\r