Added fragment to FormActionTagHelper and FormActionTagHelper
Addresses #4917
This commit is contained in:
parent
4e1ec39a1f
commit
e7c992ff06
|
|
@ -18,18 +18,21 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlTargetElement("button", Attributes = ActionAttributeName)]
|
||||
[HtmlTargetElement("button", Attributes = ControllerAttributeName)]
|
||||
[HtmlTargetElement("button", Attributes = AreaAttributeName)]
|
||||
[HtmlTargetElement("button", Attributes = FragmentAttributeName)]
|
||||
[HtmlTargetElement("button", Attributes = RouteAttributeName)]
|
||||
[HtmlTargetElement("button", Attributes = RouteValuesDictionaryName)]
|
||||
[HtmlTargetElement("button", Attributes = RouteValuesPrefix + "*")]
|
||||
[HtmlTargetElement("input", Attributes = ImageActionAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = ImageControllerAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = ImageAreaAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = ImageFragmentAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = ImageRouteAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = ImageRouteValuesDictionarySelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = ImageRouteValuesSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitActionAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitControllerAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitAreaAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitFragmentAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitRouteAttributeSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitRouteValuesDictionarySelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
[HtmlTargetElement("input", Attributes = SubmitRouteValuesSelector, TagStructure = TagStructure.WithoutEndTag)]
|
||||
|
|
@ -38,6 +41,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
private const string ActionAttributeName = "asp-action";
|
||||
private const string AreaAttributeName = "asp-area";
|
||||
private const string ControllerAttributeName = "asp-controller";
|
||||
private const string FragmentAttributeName = "asp-fragment";
|
||||
private const string RouteAttributeName = "asp-route";
|
||||
private const string RouteValuesDictionaryName = "asp-all-route-data";
|
||||
private const string RouteValuesPrefix = "asp-route-";
|
||||
|
|
@ -46,6 +50,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
private const string ImageTypeSelector = "[type=image], ";
|
||||
private const string ImageActionAttributeSelector = ImageTypeSelector + ActionAttributeName;
|
||||
private const string ImageAreaAttributeSelector = ImageTypeSelector + AreaAttributeName;
|
||||
private const string ImageFragmentAttributeSelector = ImageTypeSelector + FragmentAttributeName;
|
||||
private const string ImageControllerAttributeSelector = ImageTypeSelector + ControllerAttributeName;
|
||||
private const string ImageRouteAttributeSelector = ImageTypeSelector + RouteAttributeName;
|
||||
private const string ImageRouteValuesDictionarySelector = ImageTypeSelector + RouteValuesDictionaryName;
|
||||
|
|
@ -54,6 +59,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
private const string SubmitTypeSelector = "[type=submit], ";
|
||||
private const string SubmitActionAttributeSelector = SubmitTypeSelector + ActionAttributeName;
|
||||
private const string SubmitAreaAttributeSelector = SubmitTypeSelector + AreaAttributeName;
|
||||
private const string SubmitFragmentAttributeSelector = SubmitTypeSelector + FragmentAttributeName;
|
||||
private const string SubmitControllerAttributeSelector = SubmitTypeSelector + ControllerAttributeName;
|
||||
private const string SubmitRouteAttributeSelector = SubmitTypeSelector + RouteAttributeName;
|
||||
private const string SubmitRouteValuesDictionarySelector = SubmitTypeSelector + RouteValuesDictionaryName;
|
||||
|
|
@ -100,6 +106,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlAttributeName(AreaAttributeName)]
|
||||
public string Area { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL fragment.
|
||||
/// </summary>
|
||||
[HtmlAttributeName(FragmentAttributeName)]
|
||||
public string Fragment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the route.
|
||||
/// </summary>
|
||||
|
|
@ -134,7 +146,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
/// <remarks>Does nothing if user provides an <c>formaction</c> attribute.</remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if <c>formaction</c> attribute is provided and <see cref="Action"/>, <see cref="Controller"/>,
|
||||
/// or <see cref="Route"/> are non-<c>null</c> or if the user provided <c>asp-route-*</c> attributes.
|
||||
/// <see cref="Fragment"/> or <see cref="Route"/> are non-<c>null</c> or if the user provided <c>asp-route-*</c> attributes.
|
||||
/// Also thrown if <see cref="Route"/> and one or both of <see cref="Action"/> and <see cref="Controller"/>
|
||||
/// are non-<c>null</c>
|
||||
/// </exception>
|
||||
|
|
@ -156,6 +168,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
if (Action != null ||
|
||||
Controller != null ||
|
||||
Area != null ||
|
||||
Fragment != null ||
|
||||
Route != null ||
|
||||
(_routeValues != null && _routeValues.Count > 0))
|
||||
{
|
||||
|
|
@ -167,6 +180,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
ActionAttributeName,
|
||||
ControllerAttributeName,
|
||||
AreaAttributeName,
|
||||
FragmentAttributeName,
|
||||
RouteAttributeName,
|
||||
RouteValuesPrefix,
|
||||
FormAction));
|
||||
|
|
@ -194,7 +208,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
if (Route == null)
|
||||
{
|
||||
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
|
||||
var url = urlHelper.Action(Action, Controller, routeValues);
|
||||
var url = urlHelper.Action(Action, Controller, routeValues, protocol: null, host: null, fragment: Fragment);
|
||||
output.Attributes.SetAttribute(FormAction, url);
|
||||
}
|
||||
else if (Action != null || Controller != null)
|
||||
|
|
@ -206,12 +220,13 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
RouteAttributeName,
|
||||
ActionAttributeName,
|
||||
ControllerAttributeName,
|
||||
FormAction));
|
||||
FormAction,
|
||||
FragmentAttributeName));
|
||||
}
|
||||
else
|
||||
{
|
||||
var urlHelper = UrlHelperFactory.GetUrlHelper(ViewContext);
|
||||
var url = urlHelper.RouteUrl(Route, routeValues);
|
||||
var url = urlHelper.RouteUrl(Route, routeValues, protocol: null, host: null, fragment: Fragment);
|
||||
output.Attributes.SetAttribute(FormAction, url);
|
||||
}
|
||||
}
|
||||
|
|
|
|||
|
|
@ -16,6 +16,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlTargetElement("form", Attributes = ActionAttributeName)]
|
||||
[HtmlTargetElement("form", Attributes = AntiforgeryAttributeName)]
|
||||
[HtmlTargetElement("form", Attributes = AreaAttributeName)]
|
||||
[HtmlTargetElement("form", Attributes = FragmentAttributeName)]
|
||||
[HtmlTargetElement("form", Attributes = ControllerAttributeName)]
|
||||
[HtmlTargetElement("form", Attributes = RouteAttributeName)]
|
||||
[HtmlTargetElement("form", Attributes = RouteValuesDictionaryName)]
|
||||
|
|
@ -25,6 +26,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
private const string ActionAttributeName = "asp-action";
|
||||
private const string AntiforgeryAttributeName = "asp-antiforgery";
|
||||
private const string AreaAttributeName = "asp-area";
|
||||
private const string FragmentAttributeName = "asp-fragment";
|
||||
private const string ControllerAttributeName = "asp-controller";
|
||||
private const string RouteAttributeName = "asp-route";
|
||||
private const string RouteValuesDictionaryName = "asp-all-route-data";
|
||||
|
|
@ -78,6 +80,12 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
[HtmlAttributeName(AntiforgeryAttributeName)]
|
||||
public bool? Antiforgery { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Gets or sets the URL fragment.
|
||||
/// </summary>
|
||||
[HtmlAttributeName(FragmentAttributeName)]
|
||||
public string Fragment { get; set; }
|
||||
|
||||
/// <summary>
|
||||
/// Name of the route.
|
||||
/// </summary>
|
||||
|
|
@ -121,7 +129,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
/// <c>false</c>.
|
||||
/// </remarks>
|
||||
/// <exception cref="InvalidOperationException">
|
||||
/// Thrown if <c>action</c> attribute is provided and <see cref="Action"/> or <see cref="Controller"/> are
|
||||
/// Thrown if <c>action</c> attribute is provided and <see cref="Action"/>, <see cref="Controller"/> or <see cref="Fragment"/> are
|
||||
/// non-<c>null</c> or if the user provided <c>asp-route-*</c> attributes.
|
||||
/// </exception>
|
||||
public override void Process(TagHelperContext context, TagHelperOutput output)
|
||||
|
|
@ -148,6 +156,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
if (Action != null ||
|
||||
Controller != null ||
|
||||
Area != null ||
|
||||
Fragment != null ||
|
||||
Route != null ||
|
||||
(_routeValues != null && _routeValues.Count > 0))
|
||||
{
|
||||
|
|
@ -158,6 +167,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
HtmlActionAttributeName,
|
||||
ActionAttributeName,
|
||||
ControllerAttributeName,
|
||||
FragmentAttributeName,
|
||||
AreaAttributeName,
|
||||
RouteAttributeName,
|
||||
RouteValuesPrefix));
|
||||
|
|
@ -198,6 +208,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
ViewContext,
|
||||
Action,
|
||||
Controller,
|
||||
Fragment,
|
||||
routeValues,
|
||||
method: null,
|
||||
htmlAttributes: null);
|
||||
|
|
@ -211,7 +222,8 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
RouteAttributeName,
|
||||
ActionAttributeName,
|
||||
ControllerAttributeName,
|
||||
HtmlActionAttributeName));
|
||||
HtmlActionAttributeName,
|
||||
FragmentAttributeName));
|
||||
}
|
||||
else
|
||||
{
|
||||
|
|
@ -219,6 +231,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
ViewContext,
|
||||
Route,
|
||||
routeValues,
|
||||
Fragment,
|
||||
method: null,
|
||||
htmlAttributes: null);
|
||||
}
|
||||
|
|
|
|||
|
|
@ -43,7 +43,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot override the '{1}' attribute for {0}. A {0} with a specified '{1}' must not have attributes starting with '{6}' or an '{2}' or '{3}' or '{4}' or '{5}' attribute.
|
||||
/// Cannot override the '{1}' attribute for {0}. A {0} with a specified '{1}' must not have attributes starting with '{7}' or an '{2}', '{3}', '{4}', '{5}', or '{6}' attribute.
|
||||
/// </summary>
|
||||
internal static string FormTagHelper_CannotOverrideAction
|
||||
{
|
||||
|
|
@ -51,11 +51,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot override the '{1}' attribute for {0}. A {0} with a specified '{1}' must not have attributes starting with '{6}' or an '{2}' or '{3}' or '{4}' or '{5}' attribute.
|
||||
/// Cannot override the '{1}' attribute for {0}. A {0} with a specified '{1}' must not have attributes starting with '{7}' or an '{2}', '{3}', '{4}', '{5}', or '{6}' attribute.
|
||||
/// </summary>
|
||||
internal static string FormatFormTagHelper_CannotOverrideAction(object p0, object p1, object p2, object p3, object p4, object p5, object p6)
|
||||
internal static string FormatFormTagHelper_CannotOverrideAction(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormTagHelper_CannotOverrideAction"), p0, p1, p2, p3, p4, p5, p6);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormTagHelper_CannotOverrideAction"), p0, p1, p2, p3, p4, p5, p6, p7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -147,11 +147,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot determine an '{4}' attribute for {0}. A {0} with a specified '{1}' must not have an '{2}' or '{3}' attribute.
|
||||
/// Cannot determine an '{4}' attribute for {0}. A {0} with a specified '{1}' must not have an '{2}', '{3}', or '{5}' attribute.
|
||||
/// </summary>
|
||||
internal static string FormatFormTagHelper_CannotDetermineActionWithRouteAndActionOrControllerSpecified(object p0, object p1, object p2, object p3, object p4)
|
||||
internal static string FormatFormTagHelper_CannotDetermineActionWithRouteAndActionOrControllerSpecified(object p0, object p1, object p2, object p3, object p4, object p5)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormTagHelper_CannotDetermineActionWithRouteAndActionOrControllerSpecified"), p0, p1, p2, p3, p4);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormTagHelper_CannotDetermineActionWithRouteAndActionOrControllerSpecified"), p0, p1, p2, p3, p4, p5);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -179,11 +179,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot override the '{6}' attribute for <{0}>. <{0}> elements with a specified '{6}' must not have attributes starting with '{5}' or an '{1}', '{2}', '{3}', or '{4}' attribute.
|
||||
/// Cannot override the '{6}' attribute for <{0}>. <{0}> elements with a specified '{7}' must not have attributes starting with '{6}' or an '{1}', '{2}', '{3}', '{4}', or '{5}' attribute.
|
||||
/// </summary>
|
||||
internal static string FormatFormActionTagHelper_CannotOverrideFormAction(object p0, object p1, object p2, object p3, object p4, object p5, object p6)
|
||||
internal static string FormatFormActionTagHelper_CannotOverrideFormAction(object p0, object p1, object p2, object p3, object p4, object p5, object p6, object p7)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormActionTagHelper_CannotOverrideFormAction"), p0, p1, p2, p3, p4, p5, p6);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormActionTagHelper_CannotOverrideFormAction"), p0, p1, p2, p3, p4, p5, p6, p7);
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
|
|
@ -195,11 +195,11 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
}
|
||||
|
||||
/// <summary>
|
||||
/// Cannot determine a '{4}' attribute for <{0}>. <{0}> elements with a specified '{1}' must not have an '{2}' or '{3}' attribute.
|
||||
/// Cannot determine a '{4}' attribute for <{0}>. <{0}> elements with a specified '{1}' must not have an '{2}', '{3}', or '{5}' attribute.
|
||||
/// </summary>
|
||||
internal static string FormatFormActionTagHelper_CannotDetermineFormActionRouteActionOrControllerSpecified(object p0, object p1, object p2, object p3, object p4)
|
||||
internal static string FormatFormActionTagHelper_CannotDetermineFormActionRouteActionOrControllerSpecified(object p0, object p1, object p2, object p3, object p4, object p5)
|
||||
{
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormActionTagHelper_CannotDetermineFormActionRouteActionOrControllerSpecified"), p0, p1, p2, p3, p4);
|
||||
return string.Format(CultureInfo.CurrentCulture, GetString("FormActionTagHelper_CannotDetermineFormActionRouteActionOrControllerSpecified"), p0, p1, p2, p3, p4, p5);
|
||||
}
|
||||
|
||||
private static string GetString(string name, params string[] formatterNames)
|
||||
|
|
|
|||
|
|
@ -1,17 +1,17 @@
|
|||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
|
||||
Example:
|
||||
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
|
|
@ -26,36 +26,36 @@
|
|||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
|
|
@ -124,7 +124,7 @@
|
|||
<value>Cannot override the '{9}' attribute for {0}. An {0} with a specified '{9}' must not have attributes starting with '{8}' or an '{1}', '{2}', '{3}', '{4}', '{5}', '{6}', or '{7}' attribute.</value>
|
||||
</data>
|
||||
<data name="FormTagHelper_CannotOverrideAction" xml:space="preserve">
|
||||
<value>Cannot override the '{1}' attribute for {0}. A {0} with a specified '{1}' must not have attributes starting with '{6}' or an '{2}' or '{3}' or '{4}' or '{5}' attribute.</value>
|
||||
<value>Cannot override the '{1}' attribute for {0}. A {0} with a specified '{1}' must not have attributes starting with '{7}' or an '{2}', '{3}', '{4}', '{5}', or '{6}' attribute.</value>
|
||||
</data>
|
||||
<data name="InputTagHelper_InvalidExpressionResult" xml:space="preserve">
|
||||
<value>Unexpected '{1}' expression result type '{2}' for {0}. '{1}' must be of type '{3}' if '{4}' is '{5}'.</value>
|
||||
|
|
@ -142,15 +142,15 @@
|
|||
<value>The attribute '{0}' does not exist in the {1}.</value>
|
||||
</data>
|
||||
<data name="FormTagHelper_CannotDetermineActionWithRouteAndActionOrControllerSpecified" xml:space="preserve">
|
||||
<value>Cannot determine an '{4}' attribute for {0}. A {0} with a specified '{1}' must not have an '{2}' or '{3}' attribute.</value>
|
||||
<value>Cannot determine an '{4}' attribute for {0}. A {0} with a specified '{1}' must not have an '{2}', '{3}', or '{5}' attribute.</value>
|
||||
</data>
|
||||
<data name="PropertyOfTypeCannotBeNull" xml:space="preserve">
|
||||
<value>The '{0}' property of '{1}' must not be null.</value>
|
||||
</data>
|
||||
<data name="FormActionTagHelper_CannotOverrideFormAction" xml:space="preserve">
|
||||
<value>Cannot override the '{6}' attribute for <{0}>. <{0}> elements with a specified '{6}' must not have attributes starting with '{5}' or an '{1}', '{2}', '{3}', or '{4}' attribute.</value>
|
||||
<value>Cannot override the '{7}' attribute for <{0}>. <{0}> elements with a specified '{7}' must not have attributes starting with '{6}' or an '{1}', '{2}', '{3}', '{4}', or '{5}' attribute.</value>
|
||||
</data>
|
||||
<data name="FormActionTagHelper_CannotDetermineFormActionRouteActionOrControllerSpecified" xml:space="preserve">
|
||||
<value>Cannot determine a '{4}' attribute for <{0}>. <{0}> elements with a specified '{1}' must not have an '{2}' or '{3}' attribute.</value>
|
||||
<value>Cannot determine a '{4}' attribute for <{0}>. <{0}> elements with a specified '{1}' must not have an '{2}', '{3}', or '{5}' attribute.</value>
|
||||
</data>
|
||||
</root>
|
||||
|
|
@ -0,0 +1,51 @@
|
|||
// 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 Microsoft.AspNetCore.Mvc.Rendering;
|
||||
|
||||
namespace Microsoft.AspNetCore.Mvc.ViewFeatures
|
||||
{
|
||||
public static class DefaultHtmlGeneratorExtensions
|
||||
{
|
||||
public static TagBuilder GenerateForm(
|
||||
this IHtmlGenerator generator,
|
||||
ViewContext viewContext,
|
||||
string actionName,
|
||||
string controllerName,
|
||||
string fragment,
|
||||
object routeValues,
|
||||
string method,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var tagBuilder = generator.GenerateForm(viewContext, actionName, controllerName, routeValues, method, htmlAttributes);
|
||||
|
||||
// Append the fragment to action
|
||||
if (fragment != null)
|
||||
{
|
||||
tagBuilder.Attributes["action"] += "#" + fragment;
|
||||
}
|
||||
|
||||
return tagBuilder;
|
||||
}
|
||||
|
||||
public static TagBuilder GenerateRouteForm(
|
||||
this IHtmlGenerator generator,
|
||||
ViewContext viewContext,
|
||||
string routeName,
|
||||
object routeValues,
|
||||
string fragment,
|
||||
string method,
|
||||
object htmlAttributes)
|
||||
{
|
||||
var tagBuilder = generator.GenerateRouteForm(viewContext, routeName, routeValues, method, htmlAttributes);
|
||||
|
||||
// Append the fragment to action
|
||||
if (fragment != null)
|
||||
{
|
||||
tagBuilder.Attributes["action"] += "#" + fragment;
|
||||
}
|
||||
|
||||
return tagBuilder;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
@ -221,7 +221,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
{
|
||||
Assert.Equal("delete", param.Action, StringComparer.Ordinal);
|
||||
Assert.Equal("books", param.Controller, StringComparer.Ordinal);
|
||||
Assert.Null(param.Fragment);
|
||||
Assert.Equal("test", param.Fragment, StringComparer.Ordinal);
|
||||
Assert.Null(param.Host);
|
||||
Assert.Null(param.Protocol);
|
||||
Assert.Equal<KeyValuePair<string, object>>(expectedRouteValues, param.Values as RouteValueDictionary);
|
||||
|
|
@ -238,6 +238,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
{
|
||||
Action = "delete",
|
||||
Controller = "books",
|
||||
Fragment = "test",
|
||||
RouteValues = routeValues,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
|
|
@ -277,9 +278,9 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
.Setup(mock => mock.RouteUrl(It.IsAny<UrlRouteContext>()))
|
||||
.Callback<UrlRouteContext>(param =>
|
||||
{
|
||||
Assert.Null(param.Fragment);
|
||||
Assert.Null(param.Host);
|
||||
Assert.Null(param.Protocol);
|
||||
Assert.Equal("test", param.Fragment, StringComparer.Ordinal);
|
||||
Assert.Equal("Default", param.RouteName, StringComparer.Ordinal);
|
||||
Assert.Equal<KeyValuePair<string, object>>(expectedRouteValues, param.Values as RouteValueDictionary);
|
||||
})
|
||||
|
|
@ -294,6 +295,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
var tagHelper = new FormActionTagHelper(urlHelperFactory.Object)
|
||||
{
|
||||
Route = "Default",
|
||||
Fragment = "test",
|
||||
RouteValues = routeValues,
|
||||
ViewContext = viewContext,
|
||||
};
|
||||
|
|
@ -467,7 +469,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var expectedErrorMessage = $"Cannot override the 'formaction' attribute for <{tagName}>. <{tagName}> " +
|
||||
"elements with a specified 'formaction' must not have attributes starting with 'asp-route-' or an " +
|
||||
"'asp-action', 'asp-controller', 'asp-area', or 'asp-route' attribute.";
|
||||
"'asp-action', 'asp-controller', 'asp-area', 'asp-fragment', or 'asp-route' attribute.";
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new TagHelperAttributeList(
|
||||
|
|
@ -502,7 +504,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
|
||||
var expectedErrorMessage = $"Cannot determine a 'formaction' attribute for <{tagName}>. <{tagName}> " +
|
||||
"elements with a specified 'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";
|
||||
"elements with a specified 'asp-route' must not have an 'asp-action', 'asp-controller', or 'asp-fragment' attribute.";
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new TagHelperAttributeList(
|
||||
|
|
|
|||
|
|
@ -284,6 +284,72 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
Assert.Empty(output.PostContent.GetContent());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_AspFragmentAddsFragmentToAction()
|
||||
{
|
||||
// Arrange
|
||||
var expectedTagName = "form";
|
||||
var metadataProvider = new TestModelMetadataProvider();
|
||||
var tagHelperContext = new TagHelperContext(
|
||||
allAttributes: new TagHelperAttributeList
|
||||
{
|
||||
{ "id", "myform" },
|
||||
{ "asp-route-name", "value" },
|
||||
{ "asp-action", "index" },
|
||||
{ "asp-controller", "home" },
|
||||
{ "asp-fragment", "test" },
|
||||
{ "method", "post" },
|
||||
{ "asp-antiforgery", true }
|
||||
},
|
||||
items: new Dictionary<object, object>(),
|
||||
uniqueId: "test");
|
||||
|
||||
var output = new TagHelperOutput(
|
||||
expectedTagName,
|
||||
attributes: new TagHelperAttributeList
|
||||
{
|
||||
{ "id", "myform" },
|
||||
},
|
||||
getChildContentAsync: (useCachedResult, encoder) =>
|
||||
{
|
||||
var tagHelperContent = new DefaultTagHelperContent();
|
||||
return Task.FromResult<TagHelperContent>(tagHelperContent);
|
||||
});
|
||||
|
||||
var urlHelper = new Mock<IUrlHelper>();
|
||||
urlHelper
|
||||
.Setup(mock => mock.Action(It.IsAny<UrlActionContext>())).Returns("home/index");
|
||||
|
||||
var htmlGenerator = new TestableHtmlGenerator(metadataProvider, urlHelper.Object);
|
||||
var viewContext = TestableHtmlGenerator.GetViewContext(
|
||||
model: null,
|
||||
htmlGenerator: htmlGenerator,
|
||||
metadataProvider: metadataProvider);
|
||||
|
||||
var formTagHelper = new FormTagHelper(htmlGenerator)
|
||||
{
|
||||
Action = "index",
|
||||
Antiforgery = true,
|
||||
Controller = "home",
|
||||
Fragment = "test",
|
||||
ViewContext = viewContext,
|
||||
RouteValues =
|
||||
{
|
||||
{ "name", "value" },
|
||||
},
|
||||
};
|
||||
|
||||
// Act
|
||||
await formTagHelper.ProcessAsync(tagHelperContext, output);
|
||||
|
||||
// Assert
|
||||
|
||||
Assert.Equal("form", output.TagName);
|
||||
Assert.Equal(TagMode.StartTagAndEndTag, output.TagMode);
|
||||
var attribute = Assert.Single(output.Attributes, attr => attr.Name.Equals("action"));
|
||||
Assert.Equal("home/index#test", attribute.Value);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public async Task ProcessAsync_AspAreaAddsAreaToRouteValues()
|
||||
{
|
||||
|
|
@ -585,7 +651,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
|
||||
var expectedErrorMessage = "Cannot override the 'action' attribute for <form>. A <form> with a specified " +
|
||||
"'action' must not have attributes starting with 'asp-route-' or an " +
|
||||
"'asp-action' or 'asp-controller' or 'asp-area' or 'asp-route' attribute.";
|
||||
"'asp-action', 'asp-controller', 'asp-fragment', 'asp-area', or 'asp-route' attribute.";
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new TagHelperAttributeList(
|
||||
|
|
@ -616,7 +682,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
|||
attributes: new TagHelperAttributeList(),
|
||||
getChildContentAsync: (useCachedResult, encoder) => Task.FromResult<TagHelperContent>(null));
|
||||
var expectedErrorMessage = "Cannot determine an 'action' attribute for <form>. A <form> with a specified " +
|
||||
"'asp-route' must not have an 'asp-action' or 'asp-controller' attribute.";
|
||||
"'asp-route' must not have an 'asp-action', 'asp-controller', or 'asp-fragment' attribute.";
|
||||
|
||||
var context = new TagHelperContext(
|
||||
allAttributes: new TagHelperAttributeList(
|
||||
|
|
|
|||
Loading…
Reference in New Issue