Add the ability to specify invariant and format
Adds the ability to specify that an `<input type="..." />` for some
specific value of `type` maps to the invariant culture and/or provides
a default format.
The primary examples of usage would be the number field which wants to
use invariant culture, or datetime which wants to use invariant culture
and a format string.
\n\nCommit migrated from 60f2d563a6
This commit is contained in:
parent
2c6e1dacac
commit
3c84c57c61
|
|
@ -59,6 +59,10 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
public readonly static string ChangeAttribute = "Components.Bind.ChangeAttribute";
|
||||
|
||||
public readonly static string ExpressionAttribute = "Components.Bind.ExpressionAttribute";
|
||||
|
||||
public readonly static string IsInvariantCulture = "Components.Bind.IsInvariantCulture";
|
||||
|
||||
public readonly static string Format = "Components.Bind.Format";
|
||||
}
|
||||
|
||||
public static class ChildContent
|
||||
|
|
|
|||
|
|
@ -4,6 +4,7 @@
|
|||
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Globalization;
|
||||
|
||||
namespace Microsoft.AspNetCore.Razor.Language.Components
|
||||
{
|
||||
|
|
@ -115,6 +116,43 @@ namespace Microsoft.AspNetCore.Razor.Language.Components
|
|||
return result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets a value that indicates where the tag helper is a bind tag helper with a default
|
||||
/// culture value of <see cref="CultureInfo.InvariantCulture"/>.
|
||||
/// </summary>
|
||||
/// <param name="tagHelper">The <see cref="TagHelperDescriptor"/>.</param>
|
||||
/// <returns>
|
||||
/// <c>true</c> if this tag helper is a bind tag helper and defaults in <see cref="CultureInfo.InvariantCulture"/>
|
||||
/// </returns>
|
||||
public static bool IsInvariantCultureBindTagHelper(this TagHelperDescriptor tagHelper)
|
||||
{
|
||||
if (tagHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagHelper));
|
||||
}
|
||||
|
||||
return
|
||||
tagHelper.Metadata.TryGetValue(ComponentMetadata.Bind.IsInvariantCulture, out var text) &&
|
||||
bool.TryParse(text, out var result) &&
|
||||
result;
|
||||
}
|
||||
|
||||
/// <summary>
|
||||
/// Gets the default format value for a bind tag helper.
|
||||
/// </summary>
|
||||
/// <param name="tagHelper">The <see cref="TagHelperDescriptor"/>.</param>
|
||||
/// <returns>The format, or <c>null</c>.</returns>
|
||||
public static string GetFormat(this TagHelperDescriptor tagHelper)
|
||||
{
|
||||
if (tagHelper == null)
|
||||
{
|
||||
throw new ArgumentNullException(nameof(tagHelper));
|
||||
}
|
||||
|
||||
tagHelper.Metadata.TryGetValue(ComponentMetadata.Bind.Format, out var result);
|
||||
return result;
|
||||
}
|
||||
|
||||
public static bool IsChildContentTagHelper(this TagHelperDescriptor tagHelper)
|
||||
{
|
||||
if (tagHelper == null)
|
||||
|
|
|
|||
|
|
@ -72,6 +72,12 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
// These mappings are also provided by attributes. Primarily these are used by <input />
|
||||
// and so we have a special case for input elements and their type attributes.
|
||||
//
|
||||
// Additionally, our mappings tell us about cases like <input type="number" ... /> where
|
||||
// we need to treat the value as an invariant culture value. In general the HTML5 field
|
||||
// types use invariant culture values when interacting with the DOM, in contrast to
|
||||
// <input type="text" ... /> which is free-form text and is most likely to be
|
||||
// culture-sensitive.
|
||||
//
|
||||
// 4. For components, we have a bit of a special case. We can infer a syntax that matches
|
||||
// case #2 based on property names. So if a component provides both 'Value' and 'ValueChanged'
|
||||
// we will turn that into an instance of bind.
|
||||
|
|
@ -254,6 +260,19 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
(string)attribute.ConstructorArguments[2].Value,
|
||||
(string)attribute.ConstructorArguments[3].Value));
|
||||
}
|
||||
else if (attribute.AttributeClass == bindInputElement && attribute.ConstructorArguments.Length == 6)
|
||||
{
|
||||
results.Add(new ElementBindData(
|
||||
type.ContainingAssembly.Name,
|
||||
type.ToDisplayString(),
|
||||
"input",
|
||||
(string)attribute.ConstructorArguments[0].Value,
|
||||
(string)attribute.ConstructorArguments[1].Value,
|
||||
(string)attribute.ConstructorArguments[2].Value,
|
||||
(string)attribute.ConstructorArguments[3].Value,
|
||||
(bool)attribute.ConstructorArguments[4].Value,
|
||||
(string)attribute.ConstructorArguments[5].Value));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -287,6 +306,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
builder.Metadata[TagHelperMetadata.Runtime.Name] = ComponentMetadata.Bind.RuntimeName;
|
||||
builder.Metadata[ComponentMetadata.Bind.ValueAttribute] = entry.ValueAttribute;
|
||||
builder.Metadata[ComponentMetadata.Bind.ChangeAttribute] = entry.ChangeAttribute;
|
||||
builder.Metadata[ComponentMetadata.Bind.IsInvariantCulture] = entry.IsInvariantCulture ? bool.TrueString : bool.FalseString;
|
||||
builder.Metadata[ComponentMetadata.Bind.Format] = entry.Format;
|
||||
|
||||
if (entry.TypeAttribute != null)
|
||||
{
|
||||
|
|
@ -512,7 +533,9 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
string typeAttribute,
|
||||
string suffix,
|
||||
string valueAttribute,
|
||||
string changeAttribute)
|
||||
string changeAttribute,
|
||||
bool isInvariantCulture = false,
|
||||
string format = null)
|
||||
{
|
||||
Assembly = assembly;
|
||||
TypeName = typeName;
|
||||
|
|
@ -521,6 +544,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
Suffix = suffix;
|
||||
ValueAttribute = valueAttribute;
|
||||
ChangeAttribute = changeAttribute;
|
||||
IsInvariantCulture = isInvariantCulture;
|
||||
Format = format;
|
||||
}
|
||||
|
||||
public string Assembly { get; }
|
||||
|
|
@ -530,6 +555,8 @@ namespace Microsoft.CodeAnalysis.Razor
|
|||
public string Suffix { get; }
|
||||
public string ValueAttribute { get; }
|
||||
public string ChangeAttribute { get; }
|
||||
public bool IsInvariantCulture { get; }
|
||||
public string Format { get; }
|
||||
}
|
||||
|
||||
private class BindElementDataVisitor : SymbolVisitor
|
||||
|
|
|
|||
|
|
@ -649,6 +649,8 @@ namespace Test
|
|||
Assert.Equal("checkbox", bind.Metadata[ComponentMetadata.Bind.TypeAttribute]);
|
||||
Assert.True(bind.IsInputElementBindTagHelper());
|
||||
Assert.False(bind.IsInputElementFallbackBindTagHelper());
|
||||
Assert.False(bind.IsInvariantCultureBindTagHelper());
|
||||
Assert.Null(bind.GetFormat());
|
||||
|
||||
var rule = Assert.Single(bind.TagMatchingRules);
|
||||
Assert.Equal("input", rule.TagName);
|
||||
|
|
@ -681,6 +683,46 @@ namespace Test
|
|||
Assert.Equal(":format", parameter.DisplayName);
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_BindOnInputElementWithTypeAttributeAndSuffixAndInvariantCultureAndFormat_CreatesDescriptor()
|
||||
{
|
||||
// Arrange
|
||||
var compilation = BaseCompilation.AddSyntaxTrees(Parse(@"
|
||||
using Microsoft.AspNetCore.Components;
|
||||
|
||||
namespace Test
|
||||
{
|
||||
[BindInputElement(""number"", null, ""value"", ""onchange"", isInvariantCulture: true, format: ""0.00"")]
|
||||
public class BindAttributes
|
||||
{
|
||||
}
|
||||
}
|
||||
"));
|
||||
|
||||
Assert.Empty(compilation.GetDiagnostics());
|
||||
|
||||
var context = TagHelperDescriptorProviderContext.Create();
|
||||
context.SetCompilation(compilation);
|
||||
|
||||
var provider = new BindTagHelperDescriptorProvider();
|
||||
|
||||
// Act
|
||||
provider.Execute(context);
|
||||
|
||||
// Assert
|
||||
var matches = GetBindTagHelpers(context);
|
||||
matches = AssertAndExcludeFullyQualifiedNameMatchComponents(matches, expectedCount: 0);
|
||||
var bind = Assert.Single(matches);
|
||||
|
||||
Assert.Equal("value", bind.Metadata[ComponentMetadata.Bind.ValueAttribute]);
|
||||
Assert.Equal("onchange", bind.Metadata[ComponentMetadata.Bind.ChangeAttribute]);
|
||||
Assert.Equal("number", bind.Metadata[ComponentMetadata.Bind.TypeAttribute]);
|
||||
Assert.True(bind.IsInputElementBindTagHelper());
|
||||
Assert.False(bind.IsInputElementFallbackBindTagHelper());
|
||||
Assert.True(bind.IsInvariantCultureBindTagHelper());
|
||||
Assert.Equal("0.00", bind.GetFormat());
|
||||
}
|
||||
|
||||
[Fact]
|
||||
public void Execute_BindFallback_CreatesDescriptor()
|
||||
{
|
||||
|
|
|
|||
|
|
@ -38,10 +38,13 @@ namespace Microsoft.AspNetCore.Components
|
|||
public sealed partial class BindInputElementAttribute : System.Attribute
|
||||
{
|
||||
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute) { }
|
||||
public BindInputElementAttribute(string type, string suffix, string valueAttribute, string changeAttribute, bool isInvariantCulture, string format) { }
|
||||
public string ChangeAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public string Suffix { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public string Type { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public string ValueAttribute { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public bool IsInvariantCulture { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
public string Format { [System.Runtime.CompilerServices.CompilerGeneratedAttribute]get { throw null; } }
|
||||
}
|
||||
public static partial class BindMethods
|
||||
{
|
||||
|
|
|
|||
Loading…
Reference in New Issue