Add Switch.Microsoft.AspNetCore.Mvc.UseDateTimeTypeForDateTimeOffset quirks mode
- patch recipients can use switch to undo the #6648 fix
This commit is contained in:
parent
6041c6b966
commit
fd9cb08790
|
|
@ -18,6 +18,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
[HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
|
[HtmlTargetElement("input", Attributes = ForAttributeName, TagStructure = TagStructure.WithoutEndTag)]
|
||||||
public class InputTagHelper : TagHelper
|
public class InputTagHelper : TagHelper
|
||||||
{
|
{
|
||||||
|
internal const string UseDateTimeLocalTypeForDateTimeOffsetSwitch = "Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset";
|
||||||
private const string ForAttributeName = "asp-for";
|
private const string ForAttributeName = "asp-for";
|
||||||
private const string FormatAttributeName = "asp-format";
|
private const string FormatAttributeName = "asp-format";
|
||||||
|
|
||||||
|
|
@ -63,6 +64,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
{ "time", "{0:HH:mm:ss.fff}" },
|
{ "time", "{0:HH:mm:ss.fff}" },
|
||||||
};
|
};
|
||||||
|
|
||||||
|
static InputTagHelper()
|
||||||
|
{
|
||||||
|
if (AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled) && enabled)
|
||||||
|
{
|
||||||
|
_defaultInputTypes.Remove(nameof(DateTimeOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/// <summary>
|
/// <summary>
|
||||||
/// Creates a new <see cref="InputTagHelper"/>.
|
/// Creates a new <see cref="InputTagHelper"/>.
|
||||||
/// </summary>
|
/// </summary>
|
||||||
|
|
@ -393,8 +402,14 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
// Rfc3339 mode _may_ override EditFormatString in a limited number of cases. Happens only when
|
// Rfc3339 mode _may_ override EditFormatString in a limited number of cases. Happens only when
|
||||||
// EditFormatString has a default format i.e. came from a [DataType] attribute.
|
// EditFormatString has a default format i.e. came from a [DataType] attribute.
|
||||||
|
//
|
||||||
|
// First condition may occur when Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset
|
||||||
|
// is true in extremely rare cases: The <input/> element for a DateTimeOffset expression must have
|
||||||
|
// type ="text". Checking the switch again to remove that case.
|
||||||
if (string.Equals("text", inputType) &&
|
if (string.Equals("text", inputType) &&
|
||||||
string.Equals(nameof(DateTimeOffset), inputTypeHint, StringComparison.OrdinalIgnoreCase))
|
string.Equals(nameof(DateTimeOffset), inputTypeHint, StringComparison.OrdinalIgnoreCase) &&
|
||||||
|
!(AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled) &&
|
||||||
|
enabled))
|
||||||
{
|
{
|
||||||
// Auto-select a format that round-trips Offset and sub-Second values in a DateTimeOffset. Not
|
// Auto-select a format that round-trips Offset and sub-Second values in a DateTimeOffset. Not
|
||||||
// done if user chose the "text" type in .cshtml file or with data annotations i.e. when
|
// done if user chose the "text" type in .cshtml file or with data annotations i.e. when
|
||||||
|
|
|
||||||
|
|
@ -17,9 +17,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
{
|
{
|
||||||
public class TemplateRenderer
|
public class TemplateRenderer
|
||||||
{
|
{
|
||||||
|
public const string IEnumerableOfIFormFileName = "IEnumerable`" + nameof(IFormFile);
|
||||||
|
internal const string UseDateTimeLocalTypeForDateTimeOffsetSwitch = "Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset";
|
||||||
private const string DisplayTemplateViewPath = "DisplayTemplates";
|
private const string DisplayTemplateViewPath = "DisplayTemplates";
|
||||||
private const string EditorTemplateViewPath = "EditorTemplates";
|
private const string EditorTemplateViewPath = "EditorTemplates";
|
||||||
public const string IEnumerableOfIFormFileName = "IEnumerable`" + nameof(IFormFile);
|
|
||||||
|
|
||||||
private static readonly Dictionary<string, Func<IHtmlHelper, IHtmlContent>> _defaultDisplayActions =
|
private static readonly Dictionary<string, Func<IHtmlHelper, IHtmlContent>> _defaultDisplayActions =
|
||||||
new Dictionary<string, Func<IHtmlHelper, IHtmlContent>>(StringComparer.OrdinalIgnoreCase)
|
new Dictionary<string, Func<IHtmlHelper, IHtmlContent>>(StringComparer.OrdinalIgnoreCase)
|
||||||
|
|
@ -75,6 +76,14 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
private readonly string _templateName;
|
private readonly string _templateName;
|
||||||
private readonly bool _readOnly;
|
private readonly bool _readOnly;
|
||||||
|
|
||||||
|
static TemplateRenderer()
|
||||||
|
{
|
||||||
|
if (AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled) && enabled)
|
||||||
|
{
|
||||||
|
_defaultEditorActions.Remove(nameof(DateTimeOffset));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
public TemplateRenderer(
|
public TemplateRenderer(
|
||||||
IViewEngine viewEngine,
|
IViewEngine viewEngine,
|
||||||
IViewBufferScope bufferScope,
|
IViewBufferScope bufferScope,
|
||||||
|
|
|
||||||
|
|
@ -1,6 +1,7 @@
|
||||||
// Copyright (c) .NET Foundation. All rights reserved.
|
// 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.
|
// Licensed under the Apache License, Version 2.0. See License.txt in the project root for license information.
|
||||||
|
|
||||||
|
using System;
|
||||||
using System.Net.Http;
|
using System.Net.Http;
|
||||||
using System.Threading.Tasks;
|
using System.Threading.Tasks;
|
||||||
using Microsoft.AspNetCore.Testing;
|
using Microsoft.AspNetCore.Testing;
|
||||||
|
|
@ -10,6 +11,8 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
{
|
{
|
||||||
public class HtmlHelperOptionsTest : IClassFixture<MvcTestFixture<RazorWebSite.Startup>>
|
public class HtmlHelperOptionsTest : IClassFixture<MvcTestFixture<RazorWebSite.Startup>>
|
||||||
{
|
{
|
||||||
|
private const string UseDateTimeLocalTypeForDateTimeOffsetSwitch = "Switch.Microsoft.AspNetCore.Mvc.UseDateTimeLocalTypeForDateTimeOffset";
|
||||||
|
|
||||||
public HtmlHelperOptionsTest(MvcTestFixture<RazorWebSite.Startup> fixture)
|
public HtmlHelperOptionsTest(MvcTestFixture<RazorWebSite.Startup> fixture)
|
||||||
{
|
{
|
||||||
Client = fixture.Client;
|
Client = fixture.Client;
|
||||||
|
|
@ -21,14 +24,17 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
public async Task AppWideDefaultsInViewAndPartialView()
|
public async Task AppWideDefaultsInViewAndPartialView()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
var expectedType = enabled ? "datetime-local" : "text";
|
||||||
|
var expectedOffset = enabled ? string.Empty : "+00:00";
|
||||||
var expected =
|
var expected =
|
||||||
@"<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
|
$@"<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
|
||||||
<ul><li>A model error occurred.</li>
|
<ul><li>A model error occurred.</li>
|
||||||
</ul></div>
|
</ul></div>
|
||||||
<validationMessageElement class=""field-validation-error"">An error occurred.</validationMessageElement>
|
<validationMessageElement class=""field-validation-error"">An error occurred.</validationMessageElement>
|
||||||
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
||||||
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
||||||
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""text"" value=""2000-01-02T03:04:05.060+00:00"" /> </div>
|
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""2000-01-02T03:04:05.060{expectedOffset}"" /> </div>
|
||||||
|
|
||||||
<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
|
<div class=""validation-summary-errors""><validationSummaryElement>MySummary</validationSummaryElement>
|
||||||
<ul><li>A model error occurred.</li>
|
<ul><li>A model error occurred.</li>
|
||||||
|
|
@ -36,7 +42,7 @@ namespace Microsoft.AspNetCore.Mvc.FunctionalTests
|
||||||
<validationMessageElement class=""field-validation-error"">An error occurred.</validationMessageElement>
|
<validationMessageElement class=""field-validation-error"">An error occurred.</validationMessageElement>
|
||||||
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
||||||
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
||||||
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""text"" value=""2000-01-02T03:04:05.060+00:00"" /> </div>
|
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""2000-01-02T03:04:05.060{expectedOffset}"" /> </div>
|
||||||
|
|
||||||
False";
|
False";
|
||||||
|
|
||||||
|
|
@ -52,14 +58,16 @@ False";
|
||||||
public async Task OverrideAppWideDefaultsInViewAndPartialView()
|
public async Task OverrideAppWideDefaultsInViewAndPartialView()
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
AppContext.TryGetSwitch(UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
var expectedType = enabled ? "datetime-local" : "text";
|
||||||
var expected =
|
var expected =
|
||||||
@"<div class=""validation-summary-errors""><ValidationSummaryInView>MySummary</ValidationSummaryInView>
|
$@"<div class=""validation-summary-errors""><ValidationSummaryInView>MySummary</ValidationSummaryInView>
|
||||||
<ul><li>A model error occurred.</li>
|
<ul><li>A model error occurred.</li>
|
||||||
</ul></div>
|
</ul></div>
|
||||||
<ValidationInView class=""field-validation-error"" data-valmsg-for=""Error"" data-valmsg-replace=""true"">An error occurred.</ValidationInView>
|
<ValidationInView class=""field-validation-error"" data-valmsg-for=""Error"" data-valmsg-replace=""true"">An error occurred.</ValidationInView>
|
||||||
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
||||||
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
||||||
<div class=""editor-field""><input class=""text-box single-line"" data-val=""true"" data-val-required=""The MyDate field is required."" id=""MyDate"" name=""MyDate"" type=""text"" value=""02/01/2000 03:04:05 +00:00"" /> <ValidationInView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInView></div>
|
<div class=""editor-field""><input class=""text-box single-line"" data-val=""true"" data-val-required=""The MyDate field is required."" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""02/01/2000 03:04:05 +00:00"" /> <ValidationInView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInView></div>
|
||||||
|
|
||||||
True
|
True
|
||||||
<div class=""validation-summary-errors""><ValidationSummaryInPartialView>MySummary</ValidationSummaryInPartialView>
|
<div class=""validation-summary-errors""><ValidationSummaryInPartialView>MySummary</ValidationSummaryInPartialView>
|
||||||
|
|
@ -68,7 +76,7 @@ True
|
||||||
<ValidationInPartialView class=""field-validation-error"" data-valmsg-for=""Error"" data-valmsg-replace=""true"">An error occurred.</ValidationInPartialView>
|
<ValidationInPartialView class=""field-validation-error"" data-valmsg-for=""Error"" data-valmsg-replace=""true"">An error occurred.</ValidationInPartialView>
|
||||||
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
<input id=""Prefix!Property1"" name=""Prefix.Property1"" type=""text"" value="""" />
|
||||||
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
<div class=""editor-label""><label for=""MyDate"">MyDate</label></div>
|
||||||
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""text"" value=""02/01/2000 03:04:05 +00:00"" /> <ValidationInPartialView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInPartialView></div>
|
<div class=""editor-field""><input class=""text-box single-line"" id=""MyDate"" name=""MyDate"" type=""{expectedType}"" value=""02/01/2000 03:04:05 +00:00"" /> <ValidationInPartialView class=""field-validation-valid"" data-valmsg-for=""MyDate"" data-valmsg-replace=""true""></ValidationInPartialView></div>
|
||||||
|
|
||||||
True";
|
True";
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -21,7 +21,7 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
{
|
{
|
||||||
public class InputTagHelperTest
|
public class InputTagHelperTest
|
||||||
{
|
{
|
||||||
public static TheoryData MultiAttributeCheckBoxData
|
public static TheoryData<TagHelperAttributeList, string> MultiAttributeCheckBoxData
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
|
@ -386,10 +386,22 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
Assert.Equal(expectedTagName, output.TagName);
|
Assert.Equal(expectedTagName, output.TagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, string> Process_GeneratesFormattedOutputData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(InputTagHelper.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
return new TheoryData<string, string>
|
||||||
|
{
|
||||||
|
{ "datetime", "datetime" },
|
||||||
|
{ null, enabled ? "datetime-local" : "text" },
|
||||||
|
{ "hidden", "hidden" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("datetime", "datetime")]
|
[MemberData(nameof(Process_GeneratesFormattedOutputData))]
|
||||||
[InlineData(null, "text")]
|
|
||||||
[InlineData("hidden", "hidden")]
|
|
||||||
public void Process_GeneratesFormattedOutput(string specifiedType, string expectedType)
|
public void Process_GeneratesFormattedOutput(string specifiedType, string expectedType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
@ -1206,20 +1218,43 @@ namespace Microsoft.AspNetCore.Mvc.TagHelpers
|
||||||
Assert.Equal(expectedTagName, output.TagName);
|
Assert.Equal(expectedTagName, output.TagName);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, Html5DateRenderingMode, string, string> ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339Data
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(InputTagHelper.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
var expectedK = enabled ? string.Empty : "K";
|
||||||
|
return new TheoryData<string, Html5DateRenderingMode, string, string>
|
||||||
|
{
|
||||||
|
{ "Date", Html5DateRenderingMode.CurrentCulture, "{0:d}", "date" }, // Format from [DataType].
|
||||||
|
{ "Date", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date" },
|
||||||
|
{ "DateTime", Html5DateRenderingMode.CurrentCulture, null, "datetime-local" },
|
||||||
|
{ "DateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local" },
|
||||||
|
{ "DateTimeOffset", Html5DateRenderingMode.CurrentCulture, null, enabled ? "datetime-local" : "text" },
|
||||||
|
{
|
||||||
|
"DateTimeOffset",
|
||||||
|
Html5DateRenderingMode.Rfc3339,
|
||||||
|
$"{{0:yyyy-MM-ddTHH:mm:ss.fff{expectedK}}}",
|
||||||
|
enabled ? "datetime-local" : "text"
|
||||||
|
},
|
||||||
|
{ "DateTimeLocal", Html5DateRenderingMode.CurrentCulture, null, "datetime-local" },
|
||||||
|
{ "DateTimeLocal", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local" },
|
||||||
|
{ "Time", Html5DateRenderingMode.CurrentCulture, "{0:t}", "time" }, // Format from [DataType].
|
||||||
|
{ "Time", Html5DateRenderingMode.Rfc3339, "{0:HH:mm:ss.fff}", "time" },
|
||||||
|
{ "NullableDate", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date" },
|
||||||
|
{ "NullableDateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local" },
|
||||||
|
{
|
||||||
|
"NullableDateTimeOffset",
|
||||||
|
Html5DateRenderingMode.Rfc3339,
|
||||||
|
$"{{0:yyyy-MM-ddTHH:mm:ss.fff{expectedK}}}",
|
||||||
|
enabled ? "datetime-local" : "text"
|
||||||
|
},
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData("Date", Html5DateRenderingMode.CurrentCulture, "{0:d}", "date")] // Format from [DataType].
|
[MemberData(nameof(ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339Data))]
|
||||||
[InlineData("Date", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date")]
|
|
||||||
[InlineData("DateTime", Html5DateRenderingMode.CurrentCulture, null, "datetime-local")]
|
|
||||||
[InlineData("DateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local")]
|
|
||||||
[InlineData("DateTimeOffset", Html5DateRenderingMode.CurrentCulture, null, "text")]
|
|
||||||
[InlineData("DateTimeOffset", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fffK}", "text")]
|
|
||||||
[InlineData("DateTimeLocal", Html5DateRenderingMode.CurrentCulture, null, "datetime-local")]
|
|
||||||
[InlineData("DateTimeLocal", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local")]
|
|
||||||
[InlineData("Time", Html5DateRenderingMode.CurrentCulture, "{0:t}", "time")] // Format from [DataType].
|
|
||||||
[InlineData("Time", Html5DateRenderingMode.Rfc3339, "{0:HH:mm:ss.fff}", "time")]
|
|
||||||
[InlineData("NullableDate", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-dd}", "date")]
|
|
||||||
[InlineData("NullableDateTime", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fff}", "datetime-local")]
|
|
||||||
[InlineData("NullableDateTimeOffset", Html5DateRenderingMode.Rfc3339, "{0:yyyy-MM-ddTHH:mm:ss.fffK}", "text")]
|
|
||||||
public async Task ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339(
|
public async Task ProcessAsync_CallsGenerateTextBox_AddsExpectedAttributesForRfc3339(
|
||||||
string propertyName,
|
string propertyName,
|
||||||
Html5DateRenderingMode dateRenderingMode,
|
Html5DateRenderingMode dateRenderingMode,
|
||||||
|
|
|
||||||
|
|
@ -29,6 +29,10 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
{
|
{
|
||||||
get
|
get
|
||||||
{
|
{
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
|
||||||
|
// Tests use string properties and fall back to text template (no type attribute) when quirk is enabled.
|
||||||
|
var dateTimeOffsetType = enabled ? string.Empty : " type='text'";
|
||||||
return new TheoryData<string, string>
|
return new TheoryData<string, string>
|
||||||
{
|
{
|
||||||
{ null, "__TextBox__ class='text-box single-line'" },
|
{ null, "__TextBox__ class='text-box single-line'" },
|
||||||
|
|
@ -53,8 +57,8 @@ namespace Microsoft.AspNetCore.Mvc.ViewFeatures.Internal
|
||||||
{ "datetime", "__TextBox__ class='text-box single-line' type='datetime-local'" },
|
{ "datetime", "__TextBox__ class='text-box single-line' type='datetime-local'" },
|
||||||
{ "DateTime-local", "__TextBox__ class='text-box single-line' type='datetime-local'" },
|
{ "DateTime-local", "__TextBox__ class='text-box single-line' type='datetime-local'" },
|
||||||
{ "DATETIME-LOCAL", "__TextBox__ class='text-box single-line' type='datetime-local'" },
|
{ "DATETIME-LOCAL", "__TextBox__ class='text-box single-line' type='datetime-local'" },
|
||||||
{ "datetimeoffset", "__TextBox__ class='text-box single-line' type='text'" },
|
{ "datetimeoffset", $"__TextBox__ class='text-box single-line'{dateTimeOffsetType}" },
|
||||||
{ "DateTimeOffset", "__TextBox__ class='text-box single-line' type='text'" },
|
{ "DateTimeOffset", $"__TextBox__ class='text-box single-line'{dateTimeOffsetType}" },
|
||||||
{ "Time", "__TextBox__ class='text-box single-line' type='time'" },
|
{ "Time", "__TextBox__ class='text-box single-line' type='time'" },
|
||||||
{ "time", "__TextBox__ class='text-box single-line' type='time'" },
|
{ "time", "__TextBox__ class='text-box single-line' type='time'" },
|
||||||
{ "Byte", "__TextBox__ class='text-box single-line' type='number'" },
|
{ "Byte", "__TextBox__ class='text-box single-line' type='number'" },
|
||||||
|
|
@ -774,9 +778,12 @@ Environment.NewLine;
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("DateTimeOffset");
|
var requiredMessage = ValidationAttributeUtil.GetRequiredErrorMessage("DateTimeOffset");
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
var expectedOffset = enabled ? string.Empty : "+00:00";
|
||||||
var expectedInput = "<input class=\"HtmlEncode[[text-box single-line]]\" data-val=\"HtmlEncode[[true]]\" " +
|
var expectedInput = "<input class=\"HtmlEncode[[text-box single-line]]\" data-val=\"HtmlEncode[[true]]\" " +
|
||||||
$"data-val-required=\"HtmlEncode[[{requiredMessage}]]\" id=\"HtmlEncode[[FieldPrefix]]\" " +
|
$"data-val-required=\"HtmlEncode[[{requiredMessage}]]\" id=\"HtmlEncode[[FieldPrefix]]\" " +
|
||||||
"name=\"HtmlEncode[[FieldPrefix]]\" type=\"HtmlEncode[[datetime]]\" value=\"HtmlEncode[[2000-01-02T03:04:05.060+00:00]]\" />";
|
"name=\"HtmlEncode[[FieldPrefix]]\" type=\"HtmlEncode[[datetime]]\" " +
|
||||||
|
$"value=\"HtmlEncode[[2000-01-02T03:04:05.060{expectedOffset}]]\" />";
|
||||||
|
|
||||||
var offset = TimeSpan.FromHours(0);
|
var offset = TimeSpan.FromHours(0);
|
||||||
var model = new DateTimeOffset(
|
var model = new DateTimeOffset(
|
||||||
|
|
@ -814,14 +821,32 @@ Environment.NewLine;
|
||||||
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplateData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
var expectedOffset = enabled ? string.Empty : "-05:00";
|
||||||
|
return new TheoryData<string, string, string, string>
|
||||||
|
{
|
||||||
|
{ null, null, $"2000-01-02T03:04:05.060{expectedOffset}", enabled ? "datetime-local" : "text" },
|
||||||
|
{ "date", "{0:d}", "2000-01-02", "date" },
|
||||||
|
{ "datetime", null, "2000-01-02T03:04:05.060", "datetime-local" },
|
||||||
|
{ "datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local" },
|
||||||
|
{
|
||||||
|
"DateTimeOffset",
|
||||||
|
"{0:o}",
|
||||||
|
$"2000-01-02T03:04:05.060{expectedOffset}",
|
||||||
|
enabled ? "datetime-local" : "text"
|
||||||
|
},
|
||||||
|
{ "time", "{0:t}", "03:04:05.060", "time" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Html5DateRenderingMode.Rfc3339 is enabled by default.
|
// Html5DateRenderingMode.Rfc3339 is enabled by default.
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, null, "2000-01-02T03:04:05.060-05:00", "text")]
|
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplateData))]
|
||||||
[InlineData("date", "{0:d}", "2000-01-02", "date")]
|
|
||||||
[InlineData("datetime", null, "2000-01-02T03:04:05.060", "datetime-local")]
|
|
||||||
[InlineData("datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local")]
|
|
||||||
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.060-05:00", "text")]
|
|
||||||
[InlineData("time", "{0:t}", "03:04:05.060", "time")]
|
|
||||||
public void Editor_FindsCorrectDateOrTimeTemplate(
|
public void Editor_FindsCorrectDateOrTimeTemplate(
|
||||||
string dataTypeName,
|
string dataTypeName,
|
||||||
string editFormatString,
|
string editFormatString,
|
||||||
|
|
@ -875,14 +900,26 @@ Environment.NewLine;
|
||||||
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339Data
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
return new TheoryData<string, string, string, string>
|
||||||
|
{
|
||||||
|
{ null, null, "02/01/2000 03:04:05 -05:00", enabled ? "datetime-local" : "text" },
|
||||||
|
{ "date", "{0:d}", "02/01/2000", "date" },
|
||||||
|
{ "datetime", null, "02/01/2000 03:04:05 -05:00", "datetime-local" },
|
||||||
|
{ "datetime-local", null, "02/01/2000 03:04:05 -05:00", "datetime-local" },
|
||||||
|
{ "DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000-05:00", enabled ? "datetime-local" : "text" },
|
||||||
|
{ "time", "{0:t}", "03:04", "time" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Html5DateRenderingMode.Rfc3339 can be disabled.
|
// Html5DateRenderingMode.Rfc3339 can be disabled.
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, null, "02/01/2000 03:04:05 -05:00", "text")]
|
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339Data))]
|
||||||
[InlineData("date", "{0:d}", "02/01/2000", "date")]
|
|
||||||
[InlineData("datetime", null, "02/01/2000 03:04:05 -05:00", "datetime-local")]
|
|
||||||
[InlineData("datetime-local", null, "02/01/2000 03:04:05 -05:00", "datetime-local")]
|
|
||||||
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000-05:00", "text")]
|
|
||||||
[InlineData("time", "{0:t}", "03:04", "time")]
|
|
||||||
[ReplaceCulture]
|
[ReplaceCulture]
|
||||||
public void Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339(
|
public void Editor_FindsCorrectDateOrTimeTemplate_NotRfc3339(
|
||||||
string dataTypeName,
|
string dataTypeName,
|
||||||
|
|
@ -939,14 +976,32 @@ Environment.NewLine;
|
||||||
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
var expectedZ = enabled ? string.Empty : "Z";
|
||||||
|
return new TheoryData<string, string, string, string>
|
||||||
|
{
|
||||||
|
{ null, null, "2000-01-02T03:04:05.060", "datetime-local" },
|
||||||
|
{ "date", "{0:d}", "2000-01-02", "date" },
|
||||||
|
{ "datetime", null, "2000-01-02T03:04:05.060", "datetime-local" },
|
||||||
|
{ "datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local" },
|
||||||
|
{
|
||||||
|
"DateTimeOffset",
|
||||||
|
"{0:o}",
|
||||||
|
$"2000-01-02T03:04:05.060{expectedZ}",
|
||||||
|
enabled ? "datetime-local" : "text"
|
||||||
|
},
|
||||||
|
{ "time", "{0:t}", "03:04:05.060", "time" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Html5DateRenderingMode.Rfc3339 is enabled by default.
|
// Html5DateRenderingMode.Rfc3339 is enabled by default.
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, null, "2000-01-02T03:04:05.060", "datetime-local")]
|
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeData))]
|
||||||
[InlineData("date", "{0:d}", "2000-01-02", "date")]
|
|
||||||
[InlineData("datetime", null, "2000-01-02T03:04:05.060", "datetime-local")]
|
|
||||||
[InlineData("datetime-local", null, "2000-01-02T03:04:05.060", "datetime-local")]
|
|
||||||
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.060Z", "text")]
|
|
||||||
[InlineData("time", "{0:t}", "03:04:05.060", "time")]
|
|
||||||
public void Editor_FindsCorrectDateOrTimeTemplate_ForDateTime(
|
public void Editor_FindsCorrectDateOrTimeTemplate_ForDateTime(
|
||||||
string dataTypeName,
|
string dataTypeName,
|
||||||
string editFormatString,
|
string editFormatString,
|
||||||
|
|
@ -999,14 +1054,26 @@ Environment.NewLine;
|
||||||
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, string, string, string> Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339Data
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
return new TheoryData<string, string, string, string>
|
||||||
|
{
|
||||||
|
{ null, null, "02/01/2000 03:04:05", "datetime-local" },
|
||||||
|
{ "date", "{0:d}", "02/01/2000", "date" },
|
||||||
|
{ "datetime", null, "02/01/2000 03:04:05", "datetime-local" },
|
||||||
|
{ "datetime-local", null, "02/01/2000 03:04:05", "datetime-local" },
|
||||||
|
{ "DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000Z", enabled ? "datetime-local" : "text" },
|
||||||
|
{ "time", "{0:t}", "03:04", "time" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Html5DateRenderingMode.Rfc3339 can be disabled.
|
// Html5DateRenderingMode.Rfc3339 can be disabled.
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, null, "02/01/2000 03:04:05", "datetime-local")]
|
[MemberData(nameof(Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339Data))]
|
||||||
[InlineData("date", "{0:d}", "02/01/2000", "date")]
|
|
||||||
[InlineData("datetime", null, "02/01/2000 03:04:05", "datetime-local")]
|
|
||||||
[InlineData("datetime-local", null, "02/01/2000 03:04:05", "datetime-local")]
|
|
||||||
[InlineData("DateTimeOffset", "{0:o}", "2000-01-02T03:04:05.0600000Z", "text")]
|
|
||||||
[InlineData("time", "{0:t}", "03:04", "time")]
|
|
||||||
[ReplaceCulture]
|
[ReplaceCulture]
|
||||||
public void Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339(
|
public void Editor_FindsCorrectDateOrTimeTemplate_ForDateTimeNotRfc3339(
|
||||||
string dataTypeName,
|
string dataTypeName,
|
||||||
|
|
@ -1062,17 +1129,29 @@ Environment.NewLine;
|
||||||
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
Assert.Equal(expectedInput, HtmlContentUtilities.HtmlContentToString(result));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
public static TheoryData<string, Html5DateRenderingMode, string> Editor_AppliesNonDefaultEditFormatData
|
||||||
|
{
|
||||||
|
get
|
||||||
|
{
|
||||||
|
AppContext.TryGetSwitch(TemplateRenderer.UseDateTimeLocalTypeForDateTimeOffsetSwitch, out var enabled);
|
||||||
|
return new TheoryData<string, Html5DateRenderingMode, string>
|
||||||
|
{
|
||||||
|
{ null, Html5DateRenderingMode.CurrentCulture, enabled ? "datetime-local" : "text" },
|
||||||
|
{ null, Html5DateRenderingMode.Rfc3339, enabled ? "datetime-local" : "text" },
|
||||||
|
{ "date", Html5DateRenderingMode.CurrentCulture, "date" },
|
||||||
|
{ "date", Html5DateRenderingMode.Rfc3339, "date" },
|
||||||
|
{ "datetime", Html5DateRenderingMode.CurrentCulture, "datetime-local" },
|
||||||
|
{ "datetime", Html5DateRenderingMode.Rfc3339, "datetime-local" },
|
||||||
|
{ "datetime-local", Html5DateRenderingMode.CurrentCulture, "datetime-local" },
|
||||||
|
{ "datetime-local", Html5DateRenderingMode.Rfc3339, "datetime-local" },
|
||||||
|
{ "time", Html5DateRenderingMode.CurrentCulture, "time" },
|
||||||
|
{ "time", Html5DateRenderingMode.Rfc3339, "time" },
|
||||||
|
};
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
[Theory]
|
[Theory]
|
||||||
[InlineData(null, Html5DateRenderingMode.CurrentCulture, "text")]
|
[MemberData(nameof(Editor_AppliesNonDefaultEditFormatData))]
|
||||||
[InlineData(null, Html5DateRenderingMode.Rfc3339, "text")]
|
|
||||||
[InlineData("date", Html5DateRenderingMode.CurrentCulture, "date")]
|
|
||||||
[InlineData("date", Html5DateRenderingMode.Rfc3339, "date")]
|
|
||||||
[InlineData("datetime", Html5DateRenderingMode.CurrentCulture, "datetime-local")]
|
|
||||||
[InlineData("datetime", Html5DateRenderingMode.Rfc3339, "datetime-local")]
|
|
||||||
[InlineData("datetime-local", Html5DateRenderingMode.CurrentCulture, "datetime-local")]
|
|
||||||
[InlineData("datetime-local", Html5DateRenderingMode.Rfc3339, "datetime-local")]
|
|
||||||
[InlineData("time", Html5DateRenderingMode.CurrentCulture, "time")]
|
|
||||||
[InlineData("time", Html5DateRenderingMode.Rfc3339, "time")]
|
|
||||||
public void Editor_AppliesNonDefaultEditFormat(string dataTypeName, Html5DateRenderingMode renderingMode, string expectedType)
|
public void Editor_AppliesNonDefaultEditFormat(string dataTypeName, Html5DateRenderingMode renderingMode, string expectedType)
|
||||||
{
|
{
|
||||||
// Arrange
|
// Arrange
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue