diff options
Diffstat (limited to 'src/System.Web.Mvc/HtmlHelper.cs')
-rw-r--r-- | src/System.Web.Mvc/HtmlHelper.cs | 451 |
1 files changed, 451 insertions, 0 deletions
diff --git a/src/System.Web.Mvc/HtmlHelper.cs b/src/System.Web.Mvc/HtmlHelper.cs new file mode 100644 index 00000000..c6ab7021 --- /dev/null +++ b/src/System.Web.Mvc/HtmlHelper.cs @@ -0,0 +1,451 @@ +using System.Collections.Generic; +using System.ComponentModel; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using System.IO; +using System.Linq; +using System.Text; +using System.Web.Helpers; +using System.Web.Mvc.Properties; +using System.Web.Routing; + +namespace System.Web.Mvc +{ + public class HtmlHelper + { + public static readonly string ValidationInputCssClassName = "input-validation-error"; + public static readonly string ValidationInputValidCssClassName = "input-validation-valid"; + public static readonly string ValidationMessageCssClassName = "field-validation-error"; + public static readonly string ValidationMessageValidCssClassName = "field-validation-valid"; + public static readonly string ValidationSummaryCssClassName = "validation-summary-errors"; + public static readonly string ValidationSummaryValidCssClassName = "validation-summary-valid"; + + private DynamicViewDataDictionary _dynamicViewDataDictionary; + + public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer) + : this(viewContext, viewDataContainer, RouteTable.Routes) + { + } + + public HtmlHelper(ViewContext viewContext, IViewDataContainer viewDataContainer, RouteCollection routeCollection) + { + if (viewContext == null) + { + throw new ArgumentNullException("viewContext"); + } + if (viewDataContainer == null) + { + throw new ArgumentNullException("viewDataContainer"); + } + if (routeCollection == null) + { + throw new ArgumentNullException("routeCollection"); + } + + ViewContext = viewContext; + ViewDataContainer = viewDataContainer; + RouteCollection = routeCollection; + ClientValidationRuleFactory = (name, metadata) => ModelValidatorProviders.Providers.GetValidators(metadata ?? ModelMetadata.FromStringExpression(name, ViewData), ViewContext).SelectMany(v => v.GetClientValidationRules()); + } + + public static bool ClientValidationEnabled + { + get { return ViewContext.GetClientValidationEnabled(); } + set { ViewContext.SetClientValidationEnabled(value); } + } + + public static string IdAttributeDotReplacement + { + get { return WebPages.Html.HtmlHelper.IdAttributeDotReplacement; } + set { WebPages.Html.HtmlHelper.IdAttributeDotReplacement = value; } + } + + internal Func<string, ModelMetadata, IEnumerable<ModelClientValidationRule>> ClientValidationRuleFactory { get; set; } + + public RouteCollection RouteCollection { get; private set; } + + public static bool UnobtrusiveJavaScriptEnabled + { + get { return ViewContext.GetUnobtrusiveJavaScriptEnabled(); } + set { ViewContext.SetUnobtrusiveJavaScriptEnabled(value); } + } + + public dynamic ViewBag + { + get + { + if (_dynamicViewDataDictionary == null) + { + _dynamicViewDataDictionary = new DynamicViewDataDictionary(() => ViewData); + } + return _dynamicViewDataDictionary; + } + } + + public ViewContext ViewContext { get; private set; } + + public ViewDataDictionary ViewData + { + get { return ViewDataContainer.ViewData; } + } + + public IViewDataContainer ViewDataContainer { get; internal set; } + + public static RouteValueDictionary AnonymousObjectToHtmlAttributes(object htmlAttributes) + { + RouteValueDictionary result = new RouteValueDictionary(); + + if (htmlAttributes != null) + { + foreach (PropertyDescriptor property in TypeDescriptor.GetProperties(htmlAttributes)) + { + result.Add(property.Name.Replace('_', '-'), property.GetValue(htmlAttributes)); + } + } + + return result; + } + + public MvcHtmlString AntiForgeryToken() + { + return AntiForgeryToken(salt: null); + } + + public MvcHtmlString AntiForgeryToken(string salt) + { + return AntiForgeryToken(salt, domain: null, path: null); + } + + public MvcHtmlString AntiForgeryToken(string salt, string domain, string path) + { + return new MvcHtmlString(AntiForgery.GetHtml(ViewContext.HttpContext, salt, domain, path).ToString()); + } + + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public string AttributeEncode(string value) + { + return (!String.IsNullOrEmpty(value)) ? HttpUtility.HtmlAttributeEncode(value) : String.Empty; + } + + public string AttributeEncode(object value) + { + return AttributeEncode(Convert.ToString(value, CultureInfo.InvariantCulture)); + } + + public void EnableClientValidation() + { + EnableClientValidation(enabled: true); + } + + public void EnableClientValidation(bool enabled) + { + ViewContext.ClientValidationEnabled = enabled; + } + + public void EnableUnobtrusiveJavaScript() + { + EnableUnobtrusiveJavaScript(enabled: true); + } + + public void EnableUnobtrusiveJavaScript(bool enabled) + { + ViewContext.UnobtrusiveJavaScriptEnabled = enabled; + } + + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public string Encode(string value) + { + return (!String.IsNullOrEmpty(value)) ? HttpUtility.HtmlEncode(value) : String.Empty; + } + + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public string Encode(object value) + { + return value != null ? HttpUtility.HtmlEncode(value) : String.Empty; + } + + internal string EvalString(string key) + { + return Convert.ToString(ViewData.Eval(key), CultureInfo.CurrentCulture); + } + + internal string EvalString(string key, string format) + { + return Convert.ToString(ViewData.Eval(key, format), CultureInfo.CurrentCulture); + } + + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public string FormatValue(object value, string format) + { + return ViewDataDictionary.FormatValueInternal(value, format); + } + + internal bool EvalBoolean(string key) + { + return Convert.ToBoolean(ViewData.Eval(key), CultureInfo.InvariantCulture); + } + + internal static IView FindPartialView(ViewContext viewContext, string partialViewName, ViewEngineCollection viewEngineCollection) + { + ViewEngineResult result = viewEngineCollection.FindPartialView(viewContext, partialViewName); + if (result.View != null) + { + return result.View; + } + + StringBuilder locationsText = new StringBuilder(); + foreach (string location in result.SearchedLocations) + { + locationsText.AppendLine(); + locationsText.Append(location); + } + + throw new InvalidOperationException(String.Format(CultureInfo.CurrentCulture, + MvcResources.Common_PartialViewNotFound, partialViewName, locationsText)); + } + + public static string GenerateIdFromName(string name) + { + return GenerateIdFromName(name, IdAttributeDotReplacement); + } + + public static string GenerateIdFromName(string name, string idAttributeDotReplacement) + { + if (name == null) + { + throw new ArgumentNullException("name"); + } + + if (idAttributeDotReplacement == null) + { + throw new ArgumentNullException("idAttributeDotReplacement"); + } + + // TagBuilder.CreateSanitizedId returns null for empty strings, return String.Empty instead to avoid breaking change + if (name.Length == 0) + { + return String.Empty; + } + + return TagBuilder.CreateSanitizedId(name, idAttributeDotReplacement); + } + + public static string GenerateLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string actionName, string controllerName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) + { + return GenerateLink(requestContext, routeCollection, linkText, routeName, actionName, controllerName, null /* protocol */, null /* hostName */, null /* fragment */, routeValues, htmlAttributes); + } + + 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) + { + return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, htmlAttributes, true /* includeImplicitMvcValues */); + } + + 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) + { + string url = UrlHelper.GenerateUrl(routeName, actionName, controllerName, protocol, hostName, fragment, routeValues, routeCollection, requestContext, includeImplicitMvcValues); + TagBuilder tagBuilder = new TagBuilder("a") + { + InnerHtml = (!String.IsNullOrEmpty(linkText)) ? HttpUtility.HtmlEncode(linkText) : String.Empty + }; + tagBuilder.MergeAttributes(htmlAttributes); + tagBuilder.MergeAttribute("href", url); + return tagBuilder.ToString(TagRenderMode.Normal); + } + + public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) + { + return GenerateRouteLink(requestContext, routeCollection, linkText, routeName, null /* protocol */, null /* hostName */, null /* fragment */, routeValues, htmlAttributes); + } + + public static string GenerateRouteLink(RequestContext requestContext, RouteCollection routeCollection, string linkText, string routeName, string protocol, string hostName, string fragment, RouteValueDictionary routeValues, IDictionary<string, object> htmlAttributes) + { + return GenerateLinkInternal(requestContext, routeCollection, linkText, routeName, null /* actionName */, null /* controllerName */, protocol, hostName, fragment, routeValues, htmlAttributes, false /* includeImplicitMvcValues */); + } + + public static string GetFormMethodString(FormMethod method) + { + switch (method) + { + case FormMethod.Get: + return "get"; + case FormMethod.Post: + return "post"; + default: + return "post"; + } + } + + public static string GetInputTypeString(InputType inputType) + { + switch (inputType) + { + case InputType.CheckBox: + return "checkbox"; + case InputType.Hidden: + return "hidden"; + case InputType.Password: + return "password"; + case InputType.Radio: + return "radio"; + case InputType.Text: + return "text"; + default: + return "text"; + } + } + + internal object GetModelStateValue(string key, Type destinationType) + { + ModelState modelState; + if (ViewData.ModelState.TryGetValue(key, out modelState)) + { + if (modelState.Value != null) + { + return modelState.Value.ConvertTo(destinationType, null /* culture */); + } + } + return null; + } + + public IDictionary<string, object> GetUnobtrusiveValidationAttributes(string name) + { + return GetUnobtrusiveValidationAttributes(name, metadata: null); + } + + // Only render attributes if unobtrusive client-side validation is enabled, and then only if we've + // never rendered validation for a field with this name in this form. Also, if there's no form context, + // then we can't render the attributes (we'd have no <form> to attach them to). + public IDictionary<string, object> GetUnobtrusiveValidationAttributes(string name, ModelMetadata metadata) + { + Dictionary<string, object> results = new Dictionary<string, object>(); + + // The ordering of these 3 checks (and the early exits) is for performance reasons. + if (!ViewContext.UnobtrusiveJavaScriptEnabled) + { + return results; + } + + FormContext formContext = ViewContext.GetFormContextForClientValidation(); + if (formContext == null) + { + return results; + } + + string fullName = ViewData.TemplateInfo.GetFullHtmlFieldName(name); + if (formContext.RenderedField(fullName)) + { + return results; + } + + formContext.RenderedField(fullName, true); + + IEnumerable<ModelClientValidationRule> clientRules = ClientValidationRuleFactory(name, metadata); + UnobtrusiveValidationAttributesGenerator.GetValidationAttributes(clientRules, results); + + return results; + } + + public MvcHtmlString HttpMethodOverride(HttpVerbs httpVerb) + { + string httpMethod; + switch (httpVerb) + { + case HttpVerbs.Delete: + httpMethod = "DELETE"; + break; + case HttpVerbs.Head: + httpMethod = "HEAD"; + break; + case HttpVerbs.Put: + httpMethod = "PUT"; + break; + default: + throw new ArgumentException(MvcResources.HtmlHelper_InvalidHttpVerb, "httpVerb"); + } + + return HttpMethodOverride(httpMethod); + } + + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public MvcHtmlString HttpMethodOverride(string httpMethod) + { + if (String.IsNullOrEmpty(httpMethod)) + { + throw new ArgumentException(MvcResources.Common_NullOrEmpty, "httpMethod"); + } + if (String.Equals(httpMethod, "GET", StringComparison.OrdinalIgnoreCase) || + String.Equals(httpMethod, "POST", StringComparison.OrdinalIgnoreCase)) + { + throw new ArgumentException(MvcResources.HtmlHelper_InvalidHttpMethod, "httpMethod"); + } + + TagBuilder tagBuilder = new TagBuilder("input"); + tagBuilder.Attributes["type"] = "hidden"; + tagBuilder.Attributes["name"] = HttpRequestExtensions.XHttpMethodOverrideKey; + tagBuilder.Attributes["value"] = httpMethod; + + return tagBuilder.ToMvcHtmlString(TagRenderMode.SelfClosing); + } + + /// <summary> + /// Wraps HTML markup in an IHtmlString, which will enable HTML markup to be + /// rendered to the output without getting HTML encoded. + /// </summary> + /// <param name="value">HTML markup string.</param> + /// <returns>An IHtmlString that represents HTML markup.</returns> + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public IHtmlString Raw(string value) + { + return new HtmlString(value); + } + + /// <summary> + /// Wraps HTML markup from the string representation of an object in an IHtmlString, + /// which will enable HTML markup to be rendered to the output without getting HTML encoded. + /// </summary> + /// <param name="value">object with string representation as HTML markup</param> + /// <returns>An IHtmlString that represents HTML markup.</returns> + [SuppressMessage("Microsoft.Performance", "CA1822:MarkMembersAsStatic", Justification = "For consistency, all helpers are instance methods.")] + public IHtmlString Raw(object value) + { + return new HtmlString(value == null ? null : value.ToString()); + } + + internal virtual void RenderPartialInternal(string partialViewName, ViewDataDictionary viewData, object model, TextWriter writer, ViewEngineCollection viewEngineCollection) + { + if (String.IsNullOrEmpty(partialViewName)) + { + throw new ArgumentException(MvcResources.Common_NullOrEmpty, "partialViewName"); + } + + ViewDataDictionary newViewData = null; + + if (model == null) + { + if (viewData == null) + { + newViewData = new ViewDataDictionary(ViewData); + } + else + { + newViewData = new ViewDataDictionary(viewData); + } + } + else + { + if (viewData == null) + { + newViewData = new ViewDataDictionary(model); + } + else + { + newViewData = new ViewDataDictionary(viewData) { Model = model }; + } + } + + ViewContext newViewContext = new ViewContext(ViewContext, ViewContext.View, newViewData, ViewContext.TempData, writer); + IView view = FindPartialView(newViewContext, partialViewName, viewEngineCollection); + view.Render(newViewContext, writer); + } + } +} |