diff --git a/src/Microsoft.AspNetCore.Mvc.TagHelpers/ButtonTagHelper.cs b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ButtonTagHelper.cs new file mode 100644 index 0000000000..7fc14aead7 --- /dev/null +++ b/src/Microsoft.AspNetCore.Mvc.TagHelpers/ButtonTagHelper.cs @@ -0,0 +1,185 @@ +// Copyright (c) .NET Foundation. All rights reserved. +// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information. + +using System; +using System.Collections.Generic; +using Microsoft.AspNetCore.Mvc.Rendering; +using Microsoft.AspNetCore.Mvc.Routing; +using Microsoft.AspNetCore.Mvc.ViewFeatures; +using Microsoft.AspNetCore.Razor.TagHelpers; +using Microsoft.AspNetCore.Routing; + +namespace Microsoft.AspNetCore.Mvc.TagHelpers +{ + /// + /// implementation targeting <button> elements. + /// + [HtmlTargetElement("button", Attributes = ActionAttributeName)] + [HtmlTargetElement("button", Attributes = ControllerAttributeName)] + [HtmlTargetElement("button", Attributes = AreaAttributeName)] + [HtmlTargetElement("button", Attributes = RouteAttributeName)] + [HtmlTargetElement("button", Attributes = RouteValuesDictionaryName)] + [HtmlTargetElement("button", Attributes = RouteValuesPrefix + "*")] + public class ButtonTagHelper : TagHelper + { + private const string ActionAttributeName = "asp-action"; + private const string ControllerAttributeName = "asp-controller"; + private const string AreaAttributeName = "asp-area"; + private const string RouteAttributeName = "asp-route"; + private const string RouteValuesDictionaryName = "asp-all-route-data"; + private const string RouteValuesPrefix = "asp-route-"; + private const string FormAction = "formaction"; + private IDictionary _routeValues; + + /// + /// Creates a new . + /// + /// The . + public ButtonTagHelper(IUrlHelperFactory urlHelperFactory) + { + UrlHelperFactory = urlHelperFactory; + } + + /// + public override int Order => -1000; + + /// + /// Gets or sets the for the current request. + /// + [HtmlAttributeNotBound] + [ViewContext] + public ViewContext ViewContext { get; set; } + + protected IUrlHelperFactory UrlHelperFactory { get; } + + /// + /// The name of the action method. + /// + [HtmlAttributeName(ActionAttributeName)] + public string Action { get; set; } + + /// + /// The name of the controller. + /// + [HtmlAttributeName(ControllerAttributeName)] + public string Controller { get; set; } + + /// + /// The name of the area. + /// + [HtmlAttributeName(AreaAttributeName)] + public string Area { get; set; } + + /// + /// Name of the route. + /// + /// + /// Must be null if or is non-null. + /// + [HtmlAttributeName(RouteAttributeName)] + public string Route { get; set; } + + /// + /// Additional parameters for the route. + /// + [HtmlAttributeName(RouteValuesDictionaryName, DictionaryAttributePrefix = RouteValuesPrefix)] + public IDictionary RouteValues + { + get + { + if (_routeValues == null) + { + _routeValues = new Dictionary(StringComparer.OrdinalIgnoreCase); + } + + return _routeValues; + } + set + { + _routeValues = value; + } + } + + /// + /// Does nothing if user provides an formaction attribute. + /// + /// Thrown if formaction attribute is provided and , , + /// or are non-null or if the user provided asp-route-* attributes. + /// Also thrown if and one or both of and + /// are non-null + /// + public override void Process(TagHelperContext context, TagHelperOutput output) + { + if (context == null) + { + throw new ArgumentNullException(nameof(context)); + } + + if (output == null) + { + throw new ArgumentNullException(nameof(output)); + } + + // If "formaction" is already set, it means the user is attempting to use a normal button. + if (output.Attributes.ContainsName(FormAction)) + { + if (Action != null || Controller != null || Area != null || Route != null || RouteValues.Count != 0) + { + // User specified a formaction and one of the bound attributes; can't determine the formaction attribute. + throw new InvalidOperationException( + Resources.FormatButtonTagHelper_CannotOverrideFormAction( + "