Skip to content

Commit

Permalink
TimeSpan support in TextBox
Browse files Browse the repository at this point in the history
  • Loading branch information
tomasherceg committed Feb 19, 2024
1 parent de38b34 commit ecd9b92
Show file tree
Hide file tree
Showing 9 changed files with 62 additions and 8 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -308,6 +308,24 @@ private void AddDefaultToStringTranslations()
.Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance), args[1])
.WithAnnotation(ResultIsObservableAnnotation.Instance)
));
AddMethodTranslator(() => default(TimeSpan).ToString(), new GenericMethodCompiler(
args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingTimeOnlyToString")
.WithAnnotation(new GlobalizeResourceBindingProperty())
.Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
.WithAnnotation(ResultIsObservableAnnotation.Instance)
));
AddMethodTranslator(() => default(Nullable<TimeSpan>).ToString(), new GenericMethodCompiler(
args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingTimeOnlyToString")
.WithAnnotation(new GlobalizeResourceBindingProperty())
.Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance))
.WithAnnotation(ResultIsObservableAnnotation.Instance)
));
AddMethodTranslator(() => default(TimeSpan).ToString("fmt"), new GenericMethodCompiler(
args => new JsIdentifierExpression("dotvvm").Member("globalize").Member("bindingTimeOnlyToString")
.WithAnnotation(new GlobalizeResourceBindingProperty())
.Invoke(args[0].WithAnnotation(ShouldBeObservableAnnotation.Instance), args[1])
.WithAnnotation(ResultIsObservableAnnotation.Instance)
));

foreach (var num in ReflectionUtils.GetNumericTypes().Except(new[] { typeof(char) }))
{
Expand Down
2 changes: 1 addition & 1 deletion src/Framework/Framework/Controls/TextBox.cs
Original file line number Diff line number Diff line change
Expand Up @@ -131,7 +131,7 @@ public static FormatValueType ResolveValueType(IValueBinding? binding)
{
return FormatValueType.DateOnly;
}
else if (binding != null && (binding.ResultType == typeof(TimeOnly) || binding.ResultType == typeof(TimeOnly?)))
else if (binding != null && (binding.ResultType == typeof(TimeOnly) || binding.ResultType == typeof(TimeOnly?) || binding.ResultType == typeof(TimeSpan) || binding.ResultType == typeof(TimeSpan?)))
{
return FormatValueType.TimeOnly;
}
Expand Down
13 changes: 11 additions & 2 deletions src/Framework/Framework/Resources/Scripts/Globalize/globalize.js
Original file line number Diff line number Diff line change
Expand Up @@ -240,7 +240,8 @@ Globalize.cultures[ "default" ] = {
g: "M/d/yyyy h:mm tt",
// G is a combination of the short date ("d") and short time ("T") patterns, separated by a space
G: "M/d/yyyy h:mm:ss tt"
}
},
additionalDefaultPatterns: ["h:mm", "h:mm:ss"]
// optional fields for each calendar:
/*
monthsGenitive:
Expand Down Expand Up @@ -1536,7 +1537,7 @@ Globalize.localize = function( key, cultureSelector ) {
Globalize.parseDate = function (value, formats, culture, previousValue) {
culture = this.findClosestCulture( culture );

var date, prop, patterns;
var date, prop, patterns, pattern;
if ( formats ) {
if ( typeof formats === "string" ) {
formats = [ formats ];
Expand All @@ -1560,6 +1561,14 @@ Globalize.parseDate = function (value, formats, culture, previousValue) {
break;
}
}
if (!date) {
for ( pattern of culture.calendar.additionalDefaultPatterns) {
date = parseExact(value, pattern, culture, previousValue);
if ( date ) {
break;
}
}
}
}

return date || null;
Expand Down

Large diffs are not rendered by default.

Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,10 @@ function validateTimeSpan(value: any) {
if (typeof value === "number") {
return { value: serializeTimeSpan(value), wasCoerced: true };
}

if (value instanceof Date) {
return { value: serializeTimeOnly(value, false), wasCoerced: true };
}
}

function validateDateTimeOffset(value: any) {
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -70,8 +70,13 @@ export function serializeDateOnly(date: Date): string {
return padNumber(date.getFullYear(), 4) + "-" + padNumber(date.getMonth() + 1, 2) + "-" + padNumber(date.getDate(), 2)
}

export function serializeTimeOnly(date: Date): string {
return padNumber(date.getHours(), 2) + ':' + padNumber(date.getMinutes(), 2) + ':' + padNumber(date.getSeconds(), 2) + '.' + padNumber(date.getMilliseconds(), 3) + '0000';
export function serializeTimeOnly(date: Date, useMilliseconds: boolean = true): string {
const result = padNumber(date.getHours(), 2) + ':' + padNumber(date.getMinutes(), 2) + ':' + padNumber(date.getSeconds(), 2);
if (useMilliseconds) {
return result + '.' + padNumber(date.getMilliseconds(), 3) + '0000';
} else{
return result;
}
}

export function serializeTimeSpan(ticks: number): string {
Expand Down
1 change: 1 addition & 0 deletions src/Framework/Framework/package.json
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
"build-development": "rollup -c && npm run tsc-types",
"build-rollup": "npm run build-production && npm run build-development",
"build-production": "rollup -c --environment BUILD:production",
"build-globalize": "esbuild --minify --outfile=./Resources/Scripts/Globalize/globalize.min.js ./Resources/Scripts/Globalize/globalize.js",
"test": "jest --silent",
"tsc-check": "tsc -p . --noEmit",
"tsc-types": "tsc -d -p . --outFile ./obj/typescript-types/dotvvm.d.ts --emitDeclarationOnly --skipLibCheck"
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -49,7 +49,7 @@
TimeSpan Format: <br>
<dot:textbox ID="timespanTextbox"
ClientIDMode="Static"
Text="{value: TimeSpanValue.ToString('HH\:mm') }"
Text="{value: TimeSpanValue.ToString('HH:mm') }"
style="height: 20px; width: 200px;"/>
<dot:Literal ID="timespanValueText"
ClientIDMode="Static"
Expand Down
11 changes: 10 additions & 1 deletion src/Samples/Tests/Tests/Control/TextBoxTests.cs
Original file line number Diff line number Diff line change
Expand Up @@ -166,7 +166,7 @@ public void Control_TextBox_StringFormat(string cultureName, string url, string
AssertUI.InnerTextEquals(nullableNumberValueText, 123.123456789.ToString(culture));

var timespanTextbox = browser.First("#timespanTextbox");
AssertUI.Attribute(timespanTextbox, "value", new TimeSpan(11, 48, 25).ToString("HH:mm"));
AssertUI.Attribute(timespanTextbox, "value", new TimeSpan(11, 48, 25).ToString("h\\:mm"));

var timespanValueText = browser.First("#timespanValueText");
AssertUI.InnerTextEquals(timespanValueText, new TimeSpan(11, 48, 25).ToString());
Expand All @@ -186,23 +186,28 @@ public void Control_TextBox_StringFormat(string cultureName, string url, string
//write invalid values
dateTextBox.Clear().SendKeys("dsasdasd");
numberTextbox.Clear().SendKeys("000//a");
timespanTextbox.Clear().SendKeys("10:23");
dateTextBox.Click();

//check displayed values (behavior change in 3.0 - previous values should stay there)
AssertUI.InnerTextEquals(dateText, new DateTime(2018, 12, 27).ToString("G", culture));
AssertUI.InnerTextEquals(numberValueText, 2000.ToString(culture));
AssertUI.InnerTextEquals(timespanTextbox, new TimeSpan(10, 23, 0).ToString("h\\:mm"));
AssertUI.InnerTextEquals(timespanValueText, new TimeSpan(10, 23, 0).ToString());

AssertUI.Attribute(numberTextbox, "value", "000//a");
AssertUI.Attribute(dateTextBox, "value", "dsasdasd");

//write new valid values
dateTextBox.Clear().SendKeys(new DateTime(2018, 1, 1).ToString("d", culture));
numberTextbox.Clear().SendKeys(1000.550277.ToString(culture));
timespanTextbox.Clear().SendKeys(new TimeSpan(11, 48, 25).ToString("h\\:mm"));
dateTextBox.Click();

//check new values
AssertUI.InnerTextEquals(dateText, new DateTime(2018, 1, 1).ToString("G", culture));
AssertUI.InnerTextEquals(numberValueText, 1000.550277.ToString(culture));
AssertUI.InnerTextEquals(timespanValueText, new TimeSpan(11, 48, 0).ToString());

AssertUI.Attribute(numberTextbox, "value", 1000.550277.ToString("n4", culture));
AssertUI.Attribute(dateTextBox, "value", dateResult3);
Expand All @@ -215,6 +220,10 @@ public void Control_TextBox_StringFormat(string cultureName, string url, string
nullableDateTextBox.Clear().SendKeys(new DateTime(2020, 4, 2).ToString("d", culture)).SendKeys(Keys.Tab);
AssertUI.Attribute(nullableDateTextBox, "value", new DateTime(2020, 4, 2).ToString("G", culture));
AssertUI.InnerTextEquals(nullableDateText, new DateTime(2020, 4, 2).ToString("G", culture));

timespanTextbox.Clear().SendKeys(new TimeSpan(10, 23, 45).ToString("t", culture)).SendKeys(Keys.Tab);
AssertUI.InnerTextEquals(timespanTextbox, new TimeSpan(10, 23, 45).ToString("h\\:mm"));
AssertUI.InnerTextEquals(timespanValueText, new TimeSpan(10, 23, 45).ToString());
});
}

Expand Down

0 comments on commit ecd9b92

Please sign in to comment.