Diff
Modified: trunk/LayoutTests/ChangeLog (266778 => 266779)
--- trunk/LayoutTests/ChangeLog 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/LayoutTests/ChangeLog 2020-09-09 14:48:26 UTC (rev 266779)
@@ -1,3 +1,23 @@
+2020-09-09 Aditya Keerthi <[email protected]>
+
+ [macOS] Add editability to input type=time
+ https://bugs.webkit.org/show_bug.cgi?id=216188
+
+ Reviewed by Devin Rousso.
+
+ * TestExpectations:
+ * fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events-expected.txt: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events.html: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-keyboard-events-expected.txt: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-keyboard-events.html: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-mouse-events-expected.txt: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-mouse-events.html: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field-expected.txt: Added.
+ * fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field.html: Added.
+ * platform/mac-wk2/TestExpectations:
+ * platform/mac-wk2/fast/forms/time/time-appearance-basic-expected.txt: Rebaselined for new appearance.
+ * platform/mac-wk2/fast/forms/time/time-input-rendering-basic-expected.txt: Rebaselined for new appearance.
+
2020-09-08 Ryan Haddad <[email protected]>
Unreviewed test gardening after r266761.
Modified: trunk/LayoutTests/TestExpectations (266778 => 266779)
--- trunk/LayoutTests/TestExpectations 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/LayoutTests/TestExpectations 2020-09-09 14:48:26 UTC (rev 266779)
@@ -31,6 +31,7 @@
fast/css/ios [ Skip ]
fast/css/watchos [ Skip ]
fast/forms/date/date-editable-components [ Skip ]
+fast/forms/time/time-editable-components [ Skip ]
fast/dom/Window/watchos [ Skip ]
fast/forms/select/mac-wk2 [ Skip ]
fast/forms/textarea/ios [ Skip ]
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events-expected.txt (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events-expected.txt 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,61 @@
+Test for focus and blur events for <input type=time>
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Focus/blur using mouse
+
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 1
+
+Focus/blur using keyboard
+
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS focusEventsFired is 1
+PASS blurEventsFired is 1
+PASS focusEventsFired is 2
+PASS blurEventsFired is 1
+PASS focusEventsFired is 2
+PASS blurEventsFired is 1
+PASS focusEventsFired is 2
+PASS blurEventsFired is 1
+PASS focusEventsFired is 2
+PASS blurEventsFired is 2
+
+Focus/blur on disabled input
+
+PASS focusEventsFired is 0
+PASS blurEventsFired is 0
+PASS document.activeElement.id is "after"
+PASS focusEventsFired is 0
+PASS blurEventsFired is 0
+PASS document.activeElement.id is "before"
+PASS focusEventsFired is 0
+PASS blurEventsFired is 0
+
+Focus/blur on readonly input
+
+PASS focusEventsFired is 1
+PASS blurEventsFired is 0
+PASS document.activeElement.id is "after"
+PASS focusEventsFired is 1
+PASS blurEventsFired is 1
+PASS focusEventsFired is 1
+PASS blurEventsFired is 1
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events.html (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events.html (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events.html 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,168 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<style>
+input {
+ width: 300px;
+}
+
+input::-webkit-datetime-edit-text {
+ font-size: 30px;
+}
+
+input::-webkit-datetime-edit-hour-field {
+ font-size: 30px;
+}
+
+input::-webkit-datetime-edit-minute-field {
+ font-size: 30px;
+}
+
+input::-webkit-datetime-edit-meridiem-field {
+ font-size: 30px;
+}
+</style>
+</head>
+<body>
+
+<input id="before" type="text">
+<input id="input" type="time" value="18:30">
+<input id="after" type="text">
+
+<script>
+
+description("Test for focus and blur events for <input type=time>");
+
+blurEventsFired = 0;
+function onBlurEvent() {
+ blurEventsFired++;
+}
+
+focusEventsFired = 0;
+function onFocusEvent() {
+ focusEventsFired++;
+}
+
+function assertFocusAndBlurCount(numFocusEvents, numBlurEvents) {
+ shouldBe("focusEventsFired", numFocusEvents.toString());
+ shouldBe("blurEventsFired", numBlurEvents.toString());
+}
+
+function resetFocusAndBlurCount() {
+ blurEventsFired = 0;
+ focusEventsFired = 0;
+}
+
+function mouseClickOn(x, y) {
+ if (!window.eventSender)
+ return;
+ eventSender.mouseMoveTo(x + input.offsetLeft, y + input.offsetTop);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+}
+
+input.addEventListener("blur", onBlurEvent);
+input.addEventListener("focus", onFocusEvent);
+
+const center = input.offsetHeight / 2;
+
+debug("Focus/blur using mouse\n");
+
+// Click on hour field.
+mouseClickOn(20, center);
+assertFocusAndBlurCount(1, 0);
+// Click on minute field.
+mouseClickOn(60, center);
+assertFocusAndBlurCount(1, 0);
+// Click on AM/PM field.
+mouseClickOn(120, center);
+assertFocusAndBlurCount(1, 0);
+// Click on control, but not a specific field.
+mouseClickOn(250, center);
+assertFocusAndBlurCount(1, 0);
+// Click outside control.
+mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
+assertFocusAndBlurCount(1, 1);
+resetFocusAndBlurCount();
+
+debug("\nFocus/blur using keyboard\n");
+
+UIHelper.activateElement(before);
+// Focus on hour field.
+UIHelper.keyDown("\t");
+assertFocusAndBlurCount(1, 0);
+// Focus on minute field.
+UIHelper.keyDown("\t");
+assertFocusAndBlurCount(1, 0);
+// Focus on AM/PM field.
+UIHelper.keyDown("\t");
+assertFocusAndBlurCount(1, 0);
+// Focus out.
+UIHelper.keyDown("\t");
+assertFocusAndBlurCount(1, 1);
+// Focus on hour field.
+UIHelper.keyDown("\t", ["shiftKey"]);
+assertFocusAndBlurCount(2, 1);
+// Focus on minute field.
+UIHelper.keyDown("\t", ["shiftKey"]);
+assertFocusAndBlurCount(2, 1);
+// Focus on AM/PM field.
+UIHelper.keyDown("\t", ["shiftKey"]);
+assertFocusAndBlurCount(2, 1);
+// Focus out.
+UIHelper.keyDown("\t", ["shiftKey"]);
+assertFocusAndBlurCount(2, 2);
+resetFocusAndBlurCount();
+
+debug("\nFocus/blur on disabled input\n")
+
+input.disabled = true;
+
+UIHelper.activateElement(before);
+// Tab to focus should skip disabled input.
+UIHelper.keyDown("\t");
+assertFocusAndBlurCount(0, 0);
+shouldBeEqualToString("document.activeElement.id", "after");
+// Shift+Tab should skip disabled input.
+UIHelper.keyDown("\t", ["shiftKey"]);
+assertFocusAndBlurCount(0, 0);
+shouldBeEqualToString("document.activeElement.id", "before");
+// Clicking on any part of the control should not focus/blur events.
+mouseClickOn(20, center);
+mouseClickOn(60, center);
+mouseClickOn(120, center);
+mouseClickOn(250, center);
+mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
+assertFocusAndBlurCount(0, 0);
+resetFocusAndBlurCount();
+
+debug("\nFocus/blur on readonly input\n")
+
+input.disabled = false;
+input.readOnly = true;
+
+UIHelper.activateElement(before);
+// Tab to focus should not skip readonly input.
+UIHelper.keyDown("\t");
+assertFocusAndBlurCount(1, 0);
+UIHelper.keyDown("\t");
+UIHelper.keyDown("\t");
+UIHelper.keyDown("\t");
+shouldBeEqualToString("document.activeElement.id", "after");
+assertFocusAndBlurCount(1, 1);
+// Clicking on any part of the control should fire the appropriate events.
+mouseClickOn(20, center);
+mouseClickOn(60, center);
+mouseClickOn(120, center);
+mouseClickOn(250, center);
+mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
+assertFocusAndBlurCount(1, 1);
+resetFocusAndBlurCount();
+
+</script>
+
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-keyboard-events-expected.txt (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-keyboard-events-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-keyboard-events-expected.txt 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,72 @@
+Test for keyboard operations for <input type=time>
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Digit keys
+PASS input.value is "00:02"
+PASS changeEventsFired is 1
+PASS inputEventsFired is 1
+
+Digit keys with timeout
+PASS input.value is "14:05"
+PASS changeEventsFired is 1
+PASS inputEventsFired is 1
+
+Digit keys clamp value
+PASS input.value is "13:22"
+PASS input.value is "12:22"
+PASS input.value is "13:22"
+PASS input.value is "13:06"
+PASS input.value is "13:59"
+PASS changeEventsFired is 5
+PASS inputEventsFired is 5
+
+Left/Right arrow keys
+PASS input.value is "02:02"
+PASS input.value is "03:03"
+PASS changeEventsFired is 5
+PASS inputEventsFired is 5
+
+Up/Down arrow keys
+PASS input.value is "12:59"
+PASS input.value is "13:59"
+PASS input.value is "12:59"
+PASS input.value is "23:59"
+PASS input.value is "11:59"
+PASS input.value is "23:59"
+PASS input.value is "11:59"
+PASS changeEventsFired is 7
+PASS inputEventsFired is 7
+
+Tab key
+PASS input.value is "02:02"
+PASS document.activeElement.id is "after"
+PASS input.value is "03:03"
+PASS document.activeElement.id is "before"
+PASS changeEventsFired is 3
+PASS inputEventsFired is 3
+
+Backspace key
+PASS input.value is ""
+PASS input.value is "19:30"
+PASS changeEventsFired is 2
+PASS inputEventsFired is 2
+
+Delete key
+PASS input.value is ""
+PASS changeEventsFired is 1
+PASS inputEventsFired is 1
+
+Disabled/readonly
+PASS input.value is "09:01"
+PASS input.value is "01:01"
+PASS input.value is "01:01"
+PASS input.value is "01:02"
+PASS changeEventsFired is 2
+PASS inputEventsFired is 2
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-keyboard-events.html (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-keyboard-events.html (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-keyboard-events.html 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,175 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+
+<input id="before" type="text">
+<input id="input" type="time">
+<input id="after" type="text">
+
+<script>
+
+jsTestIsAsync = true;
+
+changeEventsFired = 0;
+function onChangeEvent() {
+ changeEventsFired++;
+}
+
+inputEventsFired = 0;
+function onInputEvent() {
+ inputEventsFired++;
+}
+
+function beginTest(title, value) {
+ debug("\n" + title);
+ input.value = value || "";
+ input.blur();
+ input.focus();
+
+ changeEventsFired = 0;
+ inputEventsFired = 0;
+}
+
+input.addEventListener("change", onChangeEvent);
+input.addEventListener("input", onInputEvent);
+
+addEventListener("load", async () => {
+ description("Test for keyboard operations for <input type=time>");
+
+ beginTest("Digit keys"); // [hh]:mm tt
+ UIHelper.keyDown("1"); // -> [01]:mm tt
+ UIHelper.keyDown("2"); // -> [12]:mm tt
+ UIHelper.keyDown("rightArrow"); // -> 12:[mm] tt
+ UIHelper.keyDown("2"); // -> 12:[02] tt
+ UIHelper.keyDown("rightArrow"); // -> 12:02 [tt]
+ UIHelper.keyDown("A"); // -> 12:02 [AM]
+ shouldBeEqualToString("input.value", "00:02");
+ shouldBe("changeEventsFired", "1");
+ shouldBe("inputEventsFired", "1");
+
+ beginTest("Digit keys with timeout"); // [hh]:mm tt
+ UIHelper.keyDown("2"); // [02]:mm tt
+ UIHelper.keyDown("rightArrow"); // -> 02:[mm] tt
+ UIHelper.keyDown("4"); // -> 02:[04] tt
+ await UIHelper.delayFor(1500); // Wait.
+ UIHelper.keyDown("5"); // -> 02:[05] tt
+ UIHelper.keyDown("rightArrow"); // -> 02:05 [tt]
+ UIHelper.keyDown("P"); // -> 02:05 [PM]
+ shouldBeEqualToString("input.value", "14:05");
+ shouldBe("changeEventsFired", "1");
+ shouldBe("inputEventsFired", "1");
+
+ beginTest("Digit keys clamp value", "12:22"); // [12]:22 PM
+ UIHelper.keyDown("1"); // -> [01]:22 PM
+ shouldBeEqualToString("input.value", "13:22");
+ UIHelper.keyDown("3"); // -> [12]:22 PM
+ shouldBeEqualToString("input.value", "12:22");
+ UIHelper.keyDown("0"); // -> [01]:22 PM
+ shouldBeEqualToString("input.value", "13:22");
+ UIHelper.keyDown("rightArrow"); // -> 13:[22] PM
+ UIHelper.keyDown("6"); // -> 13:[06] PM
+ shouldBeEqualToString("input.value", "13:06");
+ UIHelper.keyDown("1"); // -> 13:[59] PM
+ shouldBeEqualToString("input.value", "13:59");
+ shouldBe("changeEventsFired", "5");
+ shouldBe("inputEventsFired", "5");
+
+ beginTest("Left/Right arrow keys", "15:27"); // [03]:27 PM
+ UIHelper.keyDown("2"); // -> [02]:27 PM
+ UIHelper.keyDown("rightArrow"); // -> 02:[27] PM
+ UIHelper.keyDown("2"); // -> 02:[02] PM
+ UIHelper.keyDown("rightArrow"); // -> 02:02 [PM]
+ UIHelper.keyDown("A"); // -> 02:02 [AM]
+ shouldBeEqualToString("input.value", "02:02");
+ UIHelper.keyDown("leftArrow"); // -> 02:[02] AM
+ UIHelper.keyDown("3"); // -> 02:[03] AM
+ UIHelper.keyDown("leftArrow"); // -> [02]:03 AM
+ UIHelper.keyDown("3"); // -> [03]:03 AM
+ shouldBeEqualToString("input.value", "03:03");
+ shouldBe("changeEventsFired", "5");
+ shouldBe("inputEventsFired", "5");
+
+ beginTest("Up/Down arrow keys", "23:59"); // [11]:59 PM
+ UIHelper.keyDown("upArrow"); // -> [12]:59 PM
+ shouldBeEqualToString("input.value", "12:59");
+ UIHelper.keyDown("upArrow"); // -> [01]:59 PM
+ shouldBeEqualToString("input.value", "13:59");
+ UIHelper.keyDown("downArrow"); // -> [12]:59 PM
+ shouldBeEqualToString("input.value", "12:59");
+ UIHelper.keyDown("downArrow"); // -> [11]:59 PM
+ shouldBeEqualToString("input.value", "23:59");
+ UIHelper.keyDown("rightArrow"); // -> 11:[59] PM
+ UIHelper.keyDown("rightArrow"); // -> 11:59 [PM]
+ UIHelper.keyDown("upArrow"); // -> 11:59 [AM]
+ shouldBeEqualToString("input.value", "11:59");
+ UIHelper.keyDown("downArrow"); // -> 11:59 [PM]
+ shouldBeEqualToString("input.value", "23:59");
+ UIHelper.keyDown("downArrow"); // -> 11:59 [AM]
+ shouldBeEqualToString("input.value", "11:59");
+ shouldBe("changeEventsFired", "7");
+ shouldBe("inputEventsFired", "7");
+
+ beginTest("Tab key"); // [hh]:mm tt
+ UIHelper.keyDown("2"); // -> [02]:mm tt
+ UIHelper.keyDown("\t"); // -> 02:[mm] tt
+ UIHelper.keyDown("2"); // -> 02:[02] tt
+ UIHelper.keyDown("\t"); // -> 02:02 [tt]
+ UIHelper.keyDown("A"); // -> 02:02 [AM]
+ shouldBeEqualToString("input.value", "02:02");
+ UIHelper.keyDown("\t"); // Focus out.
+ shouldBeEqualToString("document.activeElement.id", "after");
+ UIHelper.keyDown("\t", ["shiftKey"]); // -> 02:02 [AM]
+ UIHelper.keyDown("\t", ["shiftKey"]); // -> 02:[02] AM
+ UIHelper.keyDown("3"); // -> 02:[03] AM
+ UIHelper.keyDown("\t", ["shiftKey"]); // -> [02]:03 AM
+ UIHelper.keyDown("3"); // -> [03]:03 AM
+ shouldBeEqualToString("input.value", "03:03");
+ UIHelper.keyDown("\t", ["shiftKey"]); // Focus out.
+ shouldBeEqualToString("document.activeElement.id", "before");
+ shouldBe("changeEventsFired", "3");
+ shouldBe("inputEventsFired", "3");
+
+ beginTest("Backspace key", "16:30"); // [04]:30 PM
+ UIHelper.keyDown("\b"); // -> [hh]:30 PM
+ shouldBeEqualToString("input.value", "");
+ UIHelper.keyDown("7"); // -> [07]:30 PM
+ shouldBeEqualToString("input.value", "19:30");
+ shouldBe("changeEventsFired", "2");
+ shouldBe("inputEventsFired", "2");
+
+ beginTest("Delete key", "18:20"); // [06]:20 PM
+ UIHelper.keyDown("delete"); // -> [hh]:20 PM
+ shouldBeEqualToString("input.value", "");
+ shouldBe("changeEventsFired", "1");
+ shouldBe("inputEventsFired", "1");
+
+ beginTest("Disabled/readonly", "09:01");
+ input.disabled = true;
+ UIHelper.keyDown("1");
+ shouldBeEqualToString("input.value", "09:01");
+ input.disabled = false;
+ input.focus();
+ UIHelper.keyDown("1");
+ shouldBeEqualToString("input.value", "01:01");
+ input.readOnly = true;
+ UIHelper.keyDown("rightArrow");
+ UIHelper.keyDown("2");
+ shouldBeEqualToString("input.value", "01:01");
+ input.readOnly = false;
+ UIHelper.keyDown("2");
+ shouldBeEqualToString("input.value", "01:02");
+ shouldBe("changeEventsFired", "2");
+ shouldBe("inputEventsFired", "2");
+
+ finishJSTest();
+});
+
+</script>
+
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-mouse-events-expected.txt (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-mouse-events-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-mouse-events-expected.txt 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,25 @@
+Test for mouse events for <input type=time>
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+Enabled Input
+
+PASS input.value is "09:30"
+PASS input.value is "09:12"
+PASS input.value is "21:12"
+PASS input.value is "18:12"
+PASS input.value is "18:12"
+PASS clickEventsFired is 4
+
+Disabled Input
+
+PASS clickEventsFired is 0
+
+Readonly Input
+
+PASS clickEventsFired is 4
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-mouse-events.html (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-mouse-events.html (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-mouse-events.html 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,122 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+<style>
+input {
+ width: 300px;
+}
+
+input::-webkit-datetime-edit-text {
+ font-size: 30px;
+}
+
+input::-webkit-datetime-edit-hour-field {
+ font-size: 30px;
+}
+
+input::-webkit-datetime-edit-minute-field {
+ font-size: 30px;
+}
+
+input::-webkit-datetime-edit-meridiem-field {
+ font-size: 30px;
+}
+</style>
+</head>
+<body>
+
+<input id="input" type="time" value="05:30">
+
+<script>
+
+description("Test for mouse events for <input type=time>");
+
+clickEventsFired = 0;
+function onClickEvent() {
+ clickEventsFired++;
+}
+
+function mouseClickOn(x, y) {
+ if (!window.eventSender)
+ return;
+ eventSender.mouseMoveTo(x + input.offsetLeft, y + input.offsetTop);
+ eventSender.mouseDown();
+ eventSender.mouseUp();
+}
+
+input.addEventListener("click", onClickEvent);
+const center = input.offsetHeight / 2;
+
+debug("Enabled Input\n");
+
+// Click on hour field.
+mouseClickOn(20, center);
+UIHelper.keyDown("9");
+shouldBeEqualToString("input.value", "09:30");
+
+// Click on minute field.
+mouseClickOn(60, center);
+UIHelper.keyDown("1");
+UIHelper.keyDown("2");
+shouldBeEqualToString("input.value", "09:12");
+
+// Click on AM/PM field.
+mouseClickOn(120, center);
+UIHelper.keyDown("upArrow");
+shouldBeEqualToString("input.value", "21:12");
+
+// Click on control, but not a specific field, defaults to first field.
+mouseClickOn(250, center);
+UIHelper.keyDown("6");
+shouldBeEqualToString("input.value", "18:12");
+
+// Click outside control.
+mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
+UIHelper.keyDown("5");
+shouldBeEqualToString("input.value", "18:12");
+
+shouldBe("clickEventsFired", "4");
+
+debug("\nDisabled Input\n");
+clickEventsFired = 0;
+input.disabled = true;
+input.readOnly = false;
+
+// Click on hour field.
+mouseClickOn(20, center);
+// Click on minute field.
+mouseClickOn(60, center);
+// Click on AM/PM field.
+mouseClickOn(120, center);
+// Click on control, but not a specific field, defaults to first field.
+mouseClickOn(250, center);
+// Click outside control.
+mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
+
+shouldBe("clickEventsFired", "0");
+
+debug("\nReadonly Input\n");
+clickEventsFired = 0;
+input.disabled = false;
+input.readOnly = true;
+
+// Click on hour field.
+mouseClickOn(20, center);
+// Click on minute field.
+mouseClickOn(60, center);
+// Click on AM/PM field.
+mouseClickOn(120, center);
+// Click on control, but not a specific field, defaults to first field.
+mouseClickOn(250, center);
+// Click outside control.
+mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
+
+shouldBe("clickEventsFired", "4");
+
+</script>
+
+<script src=""
+</body>
+</html>
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field-expected.txt (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field-expected.txt (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field-expected.txt 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,40 @@
+Test for presence of second and millisecond fields in <input type=time>
+
+On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
+
+
+
+Default
+PASS numberOfFields is 3
+
+Zero seconds
+PASS numberOfFields is 3
+
+Zero seconds and zero milliseconds
+PASS numberOfFields is 3
+
+Zero seconds and non-zero milliseconds
+PASS numberOfFields is 5
+
+Non-zero seconds
+PASS numberOfFields is 4
+
+Non-zero seconds and zero milliseconds
+PASS numberOfFields is 4
+
+Non-zero seconds and non-zero milliseconds
+PASS numberOfFields is 5
+
+Step attribute minute precision
+PASS numberOfFields is 3
+
+Step attribute second precision
+PASS numberOfFields is 4
+
+Step attribute millisecond precision
+PASS numberOfFields is 5
+
+PASS successfullyParsed is true
+
+TEST COMPLETE
+
Added: trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field.html (0 => 266779)
--- trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field.html (rev 0)
+++ trunk/LayoutTests/fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field.html 2020-09-09 14:48:26 UTC (rev 266779)
@@ -0,0 +1,89 @@
+<!DOCTYPE html>
+<html>
+<head>
+<script src=""
+<script src=""
+</head>
+<body>
+
+<input id="before" type="text">
+<input id="input" type="time">
+<input id="after" type="text">
+
+<script>
+
+jsTestIsAsync = true;
+
+function beginTest(title, value, step) {
+ debug("\n" + title);
+ input.value = value || "";
+ input.step = step || "";
+ input.blur();
+ input.focus();
+}
+
+function verifyNumberOfFields(expected) {
+ numberOfFields = 0;
+
+ // Focus first field.
+ input.blur();
+ input.focus();
+
+ while (document.activeElement !== after) {
+ numberOfFields++;
+ UIHelper.keyDown("\t");
+ }
+
+ // Return focus to first field.
+ input.blur();
+ input.focus();
+
+ shouldBe("numberOfFields", expected.toString());
+}
+
+addEventListener("load", async () => {
+ description("Test for presence of second and millisecond fields in <input type=time>");
+
+ defaultNumberOfFields = 3; // Hour, minute, and AM/PM fields
+ numberOfFieldsWithSeconds = defaultNumberOfFields + 1;
+ numberOfFieldsWithMilliseconds = numberOfFieldsWithSeconds + 1;
+
+ beginTest("Default", "10:20");
+ verifyNumberOfFields(defaultNumberOfFields);
+
+ beginTest("Zero seconds", "10:20:00");
+ verifyNumberOfFields(defaultNumberOfFields);
+
+ beginTest("Zero seconds and zero milliseconds", "10:20:00.000");
+ verifyNumberOfFields(defaultNumberOfFields);
+
+ beginTest("Zero seconds and non-zero milliseconds", "10:20:00.567");
+ verifyNumberOfFields(numberOfFieldsWithMilliseconds);
+
+ beginTest("Non-zero seconds", "10:20:45");
+ verifyNumberOfFields(numberOfFieldsWithSeconds);
+
+ beginTest("Non-zero seconds and zero milliseconds", "10:20:45.000");
+ verifyNumberOfFields(numberOfFieldsWithSeconds);
+
+ beginTest("Non-zero seconds and non-zero milliseconds", "10:20:45.567");
+ verifyNumberOfFields(numberOfFieldsWithMilliseconds);
+
+ beginTest("Step attribute minute precision", "10:20", "60");
+ verifyNumberOfFields(defaultNumberOfFields);
+
+ beginTest("Step attribute second precision", "10:20", "2");
+ verifyNumberOfFields(numberOfFieldsWithSeconds);
+
+ beginTest("Step attribute millisecond precision", "10:20", "0.5");
+ verifyNumberOfFields(numberOfFieldsWithMilliseconds);
+
+ debug("");
+ finishJSTest();
+});
+
+</script>
+
+<script src=""
+</body>
+</html>
Modified: trunk/LayoutTests/platform/mac-wk2/TestExpectations (266778 => 266779)
--- trunk/LayoutTests/platform/mac-wk2/TestExpectations 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/LayoutTests/platform/mac-wk2/TestExpectations 2020-09-09 14:48:26 UTC (rev 266779)
@@ -13,6 +13,7 @@
editing/pasteboard/dom-paste [ Pass ]
fast/events/cursors [ Pass ]
fast/forms/date/date-editable-components [ Pass ]
+fast/forms/time/time-editable-components [ Pass ]
fast/forms/select/mac-wk2 [ Pass ]
fast/sandbox/mac [ Pass ]
fast/scrolling/mac [ Pass ]
Modified: trunk/LayoutTests/platform/mac-wk2/fast/forms/time/time-appearance-basic-expected.txt (266778 => 266779)
--- trunk/LayoutTests/platform/mac-wk2/fast/forms/time/time-appearance-basic-expected.txt 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/LayoutTests/platform/mac-wk2/fast/forms/time/time-appearance-basic-expected.txt 2020-09-09 14:48:26 UTC (rev 266779)
@@ -4,7 +4,7 @@
step=60
step=3600
step=86400
-step mismatched
+step mismatched
RTL
Disabled, step=3600
Readonly, step=3600
Modified: trunk/LayoutTests/platform/mac-wk2/fast/forms/time/time-input-rendering-basic-expected.txt (266778 => 266779)
--- trunk/LayoutTests/platform/mac-wk2/fast/forms/time/time-input-rendering-basic-expected.txt 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/LayoutTests/platform/mac-wk2/fast/forms/time/time-input-rendering-basic-expected.txt 2020-09-09 14:48:26 UTC (rev 266779)
@@ -3,10 +3,46 @@
layer at (0,0) size 800x600
RenderBlock {HTML} at (0,0) size 800x600
RenderBody {BODY} at (8,8) size 784x584
- RenderText {#text} at (110,0) size 4x18
- text run at (110,0) width 4: " "
+ RenderText {#text} at (110,2) size 4x18
+ text run at (110,2) width 4: " "
RenderText {#text} at (0,0) size 0x0
-layer at (8,19) size 110x6 clip at (10,21) size 106x2
- RenderFlexibleBox {INPUT} at (0,11) size 110x6 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
-layer at (122,19) size 110x6 clip at (124,21) size 106x2
- RenderFlexibleBox {INPUT} at (114,11) size 110x6 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
+layer at (8,10) size 110x19 clip at (10,12) size 106x15
+ RenderFlexibleBox {INPUT} at (0,2) size 110x19 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
+layer at (11,13) size 56x13 scrollHeight 14
+ RenderBlock {DIV} at (3,3) size 56x13
+ RenderBlock {DIV} at (0,0) size 56x13
+ RenderInline {DIV} at (0,0) size 17x15
+ RenderText {#text} at (1,0) size 15x13
+ text run at (1,0) width 15: "09"
+ RenderInline {DIV} at (0,0) size 4x13
+ RenderText {#text} at (16,0) size 4x13
+ text run at (16,0) width 4: ":"
+ RenderInline {DIV} at (0,0) size 15x15
+ RenderText {#text} at (20,0) size 13x13
+ text run at (20,0) width 13: "41"
+ RenderInline {DIV} at (0,0) size 4x13
+ RenderText {#text} at (33,0) size 4x13
+ text run at (33,0) width 4: " "
+ RenderInline {DIV} at (0,0) size 20x15
+ RenderText {#text} at (37,0) size 18x13
+ text run at (37,0) width 18: "AM"
+layer at (122,10) size 110x19 clip at (124,12) size 106x15
+ RenderFlexibleBox {INPUT} at (114,2) size 110x19 [bgcolor=#FFFFFF] [border: (2px inset #000000)]
+layer at (173,13) size 56x13 scrollHeight 14
+ RenderBlock {DIV} at (51,3) size 56x13
+ RenderBlock {DIV} at (0,0) size 56x13
+ RenderInline {DIV} at (0,0) size 17x15
+ RenderText {#text} at (23,0) size 15x13
+ text run at (23,0) width 15: "09"
+ RenderInline {DIV} at (0,0) size 4x13
+ RenderText {#text} at (38,0) size 4x13
+ text run at (38,0) width 4: ":"
+ RenderInline {DIV} at (0,0) size 15x15
+ RenderText {#text} at (42,0) size 13x13
+ text run at (42,0) width 13: "41"
+ RenderInline {DIV} at (0,0) size 4x13
+ RenderText {#text} at (19,0) size 4x13
+ text run at (19,0) width 4 RTL: " "
+ RenderInline {DIV} at (0,0) size 20x15
+ RenderText {#text} at (1,0) size 18x13
+ text run at (1,0) width 18: "AM"
Modified: trunk/Source/WebCore/ChangeLog (266778 => 266779)
--- trunk/Source/WebCore/ChangeLog 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/ChangeLog 2020-09-09 14:48:26 UTC (rev 266779)
@@ -1,3 +1,117 @@
+2020-09-09 Aditya Keerthi <[email protected]>
+
+ [macOS] Add editability to input type=time
+ https://bugs.webkit.org/show_bug.cgi?id=216188
+
+ Reviewed by Devin Rousso.
+
+ This patch adds editability to input type=time by leveraging existing
+ logic to add editable components to date/time inputs.
+
+ DateTime{Hour|Minute|Second|Millisecond|Meridiem}FieldElements were
+ created to represent the new editable fields. By default, only the
+ hour and minute fields are displayed. However, the millisecond
+ and second fields may be added depending on the initial value of
+ the element, or the value of the step attribute.
+
+ Tests: fast/forms/time/time-editable-components/time-editable-components-focus-and-blur-events.html
+ fast/forms/time/time-editable-components/time-editable-components-keyboard-events.html
+ fast/forms/time/time-editable-components/time-editable-components-mouse-events.html
+ fast/forms/time/time-editable-components/time-editable-components-second-and-millisecond-field.html
+
+ * css/html.css:
+
+ Update stylesheet to handle hour, minute, second, millisecond and meridiem fields.
+
+ (input::-webkit-datetime-edit-fields-wrapper):
+ (input::-webkit-datetime-edit-year-field,):
+ (input::-webkit-datetime-edit-year-field:focus,):
+ (input[disabled]::-webkit-datetime-edit-year-field,):
+ * html/BaseChooserOnlyDateAndTimeInputType.cpp:
+ (WebCore::DateTimeFormatValidator::visitField):
+ (WebCore::BaseChooserOnlyDateAndTimeInputType::updateInnerTextValue):
+ (WebCore::BaseChooserOnlyDateAndTimeInputType::attributeChanged):
+
+ The step attribute can determine whether the second and/or millisecond
+ fields are displayed. Consequently, we should update the fields in
+ m_dateTimeEditElement when the step attribute is changed.
+
+ * html/BaseChooserOnlyDateAndTimeInputType.h:
+
+ setupLayoutParameters() now takes an additional DateComponents argument.
+ This argument is needed to determine whether the second and/or
+ millisecond field is displayed.
+
+ * html/BaseDateAndTimeInputType.h:
+ * html/DateInputType.cpp:
+ (WebCore::DateInputType::setupLayoutParameters const):
+ * html/DateInputType.h:
+ * html/DateTimeFieldsState.h:
+ * html/DateTimeLocalInputType.cpp:
+ (WebCore::DateTimeLocalInputType::setupLayoutParameters const):
+ * html/DateTimeLocalInputType.h:
+ * html/MonthInputType.cpp:
+ (WebCore::MonthInputType::setupLayoutParameters const):
+ * html/MonthInputType.h:
+ * html/TimeInputType.cpp:
+ (WebCore::TimeInputType::isValidFormat const):
+ (WebCore::TimeInputType::formatDateTimeFieldsState const):
+ (WebCore::TimeInputType::setupLayoutParameters const):
+
+ The millisecond field is displayed if the date has a non-zero value for
+ milliseconds, or if the step attribute has sub-second precision. The
+ second field is displayed if the millisecond field is displayed, if the
+ date has a non-zero value for seconds, or if the step attribute has
+ sub-minute precision.
+
+ * html/TimeInputType.h:
+ * html/WeekInputType.cpp:
+ (WebCore::WeekInputType::setupLayoutParameters const):
+ * html/WeekInputType.h:
+ * html/shadow/DateTimeEditElement.cpp:
+ (WebCore::DateTimeEditBuilder::visitField): Updated to add new field types to the element.
+ * html/shadow/DateTimeEditElement.h:
+ * html/shadow/DateTimeFieldElements.cpp:
+ (WebCore::DateTimeHourFieldElement::DateTimeHourFieldElement):
+ (WebCore::DateTimeHourFieldElement::create):
+ (WebCore::DateTimeHourFieldElement::populateDateTimeFieldsState):
+ (WebCore::DateTimeHourFieldElement::setValueAsDate):
+ (WebCore::DateTimeMeridiemFieldElement::DateTimeMeridiemFieldElement):
+ (WebCore::DateTimeMeridiemFieldElement::create):
+ (WebCore::DateTimeMeridiemFieldElement::populateDateTimeFieldsState):
+ (WebCore::DateTimeMeridiemFieldElement::setValueAsDate):
+ (WebCore::DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement):
+ (WebCore::DateTimeMillisecondFieldElement::create):
+ (WebCore::DateTimeMillisecondFieldElement::populateDateTimeFieldsState):
+ (WebCore::DateTimeMillisecondFieldElement::setValueAsDate):
+ (WebCore::DateTimeMinuteFieldElement::DateTimeMinuteFieldElement):
+ (WebCore::DateTimeMinuteFieldElement::create):
+ (WebCore::DateTimeMinuteFieldElement::populateDateTimeFieldsState):
+ (WebCore::DateTimeMinuteFieldElement::setValueAsDate):
+ (WebCore::DateTimeSecondFieldElement::DateTimeSecondFieldElement):
+ (WebCore::DateTimeSecondFieldElement::create):
+ (WebCore::DateTimeSecondFieldElement::populateDateTimeFieldsState):
+ (WebCore::DateTimeSecondFieldElement::setValueAsDate):
+ * html/shadow/DateTimeFieldElements.h:
+ * html/shadow/DateTimeNumericFieldElement.cpp:
+ (WebCore::DateTimeNumericFieldElement::maximum const):
+ * html/shadow/DateTimeNumericFieldElement.h:
+ * html/shadow/DateTimeSymbolicFieldElement.cpp:
+ (WebCore::DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement):
+ (WebCore::DateTimeSymbolicFieldElement::handleKeyboardEvent): Implement editing using the same typeahead behavior as <select> elements.
+ (WebCore::DateTimeSymbolicFieldElement::indexOfSelectedOption const):
+ (WebCore::DateTimeSymbolicFieldElement::optionCount const):
+ (WebCore::DateTimeSymbolicFieldElement::optionAtIndex const):
+ * html/shadow/DateTimeSymbolicFieldElement.h:
+ * platform/text/PlatformLocale.cpp:
+ (WebCore::Locale::localizedDecimalSeparator):
+
+ Added method to ensure the correct decimal separator is displayed
+ depending on the user's locale. This separator is used when
+ the millisecond field is present.
+
+ * platform/text/PlatformLocale.h:
+
2020-09-08 Ryosuke Niwa <[email protected]>
Node flags should be an OptionSet
Modified: trunk/Source/WebCore/css/html.css (266778 => 266779)
--- trunk/Source/WebCore/css/html.css 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/css/html.css 2020-09-09 14:48:26 UTC (rev 266779)
@@ -497,11 +497,17 @@
input::-webkit-datetime-edit-fields-wrapper {
display: inline-block;
+ white-space: pre;
}
input::-webkit-datetime-edit-year-field,
input::-webkit-datetime-edit-month-field,
-input::-webkit-datetime-edit-day-field {
+input::-webkit-datetime-edit-day-field,
+input::-webkit-datetime-edit-hour-field,
+input::-webkit-datetime-edit-minute-field,
+input::-webkit-datetime-edit-second-field,
+input::-webkit-datetime-edit-millisecond-field,
+input::-webkit-datetime-edit-meridiem-field {
display: inline;
padding: 1px;
}
@@ -508,7 +514,12 @@
input::-webkit-datetime-edit-year-field:focus,
input::-webkit-datetime-edit-month-field:focus,
-input::-webkit-datetime-edit-day-field:focus {
+input::-webkit-datetime-edit-day-field:focus,
+input::-webkit-datetime-edit-hour-field:focus,
+input::-webkit-datetime-edit-minute-field:focus,
+input::-webkit-datetime-edit-second-field:focus,
+input::-webkit-datetime-edit-millisecond-field:focus,
+input::-webkit-datetime-edit-meridiem-field:focus {
#if defined(WTF_PLATFORM_COCOA) && WTF_PLATFORM_COCOA
background-color: -apple-system-control-accent;
color: white;
@@ -522,6 +533,11 @@
input[disabled]::-webkit-datetime-edit-year-field,
input[disabled]::-webkit-datetime-edit-month-field,
input[disabled]::-webkit-datetime-edit-day-field,
+input[disabled]::-webkit-datetime-edit-hour-field,
+input[disabled]::-webkit-datetime-edit-minute-field,
+input[disabled]::-webkit-datetime-edit-second-field,
+input[disabled]::-webkit-datetime-edit-millisecond-field,
+input[disabled]::-webkit-datetime-edit-meridiem-field,
input[disabled]::-webkit-datetime-edit-text {
color: GrayText;
}
Modified: trunk/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -40,6 +40,7 @@
#include "RenderElement.h"
#include "Settings.h"
#include "ShadowRoot.h"
+#include "StepRange.h"
#include "Text.h"
#include "UserGestureIndicator.h"
#include <wtf/NeverDestroyed.h>
@@ -80,7 +81,7 @@
break;
case DateTimeFormat::FieldTypePeriod:
- m_results.add(DateTimeFormatValidationResults::HasAMPM);
+ m_results.add(DateTimeFormatValidationResults::HasMeridiem);
break;
case DateTimeFormat::FieldTypeHour11:
@@ -91,7 +92,7 @@
case DateTimeFormat::FieldTypeHour23:
case DateTimeFormat::FieldTypeHour24:
m_results.add(DateTimeFormatValidationResults::HasHour);
- m_results.add(DateTimeFormatValidationResults::HasAMPM);
+ m_results.add(DateTimeFormatValidationResults::HasMeridiem);
break;
case DateTimeFormat::FieldTypeMinute:
@@ -192,12 +193,21 @@
}
DateTimeEditElement::LayoutParameters layoutParameters(element()->locale());
- setupLayoutParameters(layoutParameters);
+ auto date = parseToDateComponents(element()->value());
+ if (date)
+ setupLayoutParameters(layoutParameters, *date);
+ else {
+ if (auto dateForLayout = setMillisecondToDateComponents(createStepRange(AnyStepHandling::Default).minimum().toDouble()))
+ setupLayoutParameters(layoutParameters, *dateForLayout);
+ else
+ setupLayoutParameters(layoutParameters, DateComponents());
+ }
+
if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this))
layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat;
- if (auto date = parseToDateComponents(element()->value()))
+ if (date)
m_dateTimeEditElement->setValueAsDate(layoutParameters, *date);
else
m_dateTimeEditElement->setEmptyValue(layoutParameters);
@@ -298,7 +308,9 @@
if (!element->hasDirtyValue())
updateInnerTextValue();
}
- }
+ } else if (name == stepAttr && m_dateTimeEditElement)
+ updateInnerTextValue();
+
BaseDateAndTimeInputType::attributeChanged(name);
}
Modified: trunk/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -42,7 +42,7 @@
HasMonth = 1 << 1,
HasWeek = 1 << 2,
HasDay = 1 << 3,
- HasAMPM = 1 << 4,
+ HasMeridiem = 1 << 4,
HasHour = 1 << 5,
HasMinute = 1 << 6,
HasSecond = 1 << 7,
@@ -56,7 +56,7 @@
explicit BaseChooserOnlyDateAndTimeInputType(HTMLInputElement& element) : BaseDateAndTimeInputType(element) { }
~BaseChooserOnlyDateAndTimeInputType();
- virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const = 0;
+ virtual void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const = 0;
private:
void updateInnerTextValue() override;
Modified: trunk/Source/WebCore/html/BaseDateAndTimeInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/BaseDateAndTimeInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/BaseDateAndTimeInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -53,10 +53,9 @@
bool isKeyboardFocusable(KeyboardEvent*) const override;
virtual Optional<DateComponents> parseToDateComponents(const StringView&) const = 0;
+ virtual Optional<DateComponents> setMillisecondToDateComponents(double) const = 0;
private:
- virtual Optional<DateComponents> setMillisecondToDateComponents(double) const = 0;
-
double valueAsDate() const override;
ExceptionOr<void> setValueAsDate(double) const override;
double valueAsDouble() const override;
Modified: trunk/Source/WebCore/html/DateInputType.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/DateInputType.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/DateInputType.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -102,7 +102,7 @@
return makeString(pad('0', 4, *state.year), '-', pad('0', 2, *state.month), '-', pad('0', 2, *state.dayOfMonth));
}
-void DateInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters) const
+void DateInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents&) const
{
layoutParameters.dateTimeFormat = layoutParameters.locale.dateFormat();
layoutParameters.fallbackDateTimeFormat = "yyyy-MM-dd"_s;
Modified: trunk/Source/WebCore/html/DateInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/DateInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/DateInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -50,7 +50,7 @@
bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
- void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
+ void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const final;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/DateTimeFieldsState.h (266778 => 266779)
--- trunk/Source/WebCore/html/DateTimeFieldsState.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/DateTimeFieldsState.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -33,9 +33,19 @@
namespace WebCore {
struct DateTimeFieldsState {
+ enum class Meridiem : bool {
+ AM,
+ PM,
+ };
+
Optional<unsigned> year;
Optional<unsigned> month;
Optional<unsigned> dayOfMonth;
+ Optional<unsigned> hour;
+ Optional<unsigned> minute;
+ Optional<unsigned> second;
+ Optional<unsigned> millisecond;
+ Optional<Meridiem> meridiem;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/DateTimeLocalInputType.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/DateTimeLocalInputType.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/DateTimeLocalInputType.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -106,7 +106,7 @@
return emptyString();
}
-void DateTimeLocalInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
+void DateTimeLocalInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const
{
}
Modified: trunk/Source/WebCore/html/DateTimeLocalInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/DateTimeLocalInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/DateTimeLocalInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -52,7 +52,7 @@
bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
- void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
+ void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const final;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/MonthInputType.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/MonthInputType.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/MonthInputType.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -144,7 +144,7 @@
return emptyString();
}
-void MonthInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
+void MonthInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const
{
}
Modified: trunk/Source/WebCore/html/MonthInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/MonthInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/MonthInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -55,7 +55,7 @@
bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
- void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
+ void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const final;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/TimeInputType.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/TimeInputType.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/TimeInputType.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -33,6 +33,7 @@
#include "TimeInputType.h"
#include "DateComponents.h"
+#include "DateTimeFieldsState.h"
#include "Decimal.h"
#include "HTMLInputElement.h"
#include "HTMLNames.h"
@@ -112,16 +113,48 @@
bool TimeInputType::isValidFormat(OptionSet<DateTimeFormatValidationResults> results) const
{
- return results.containsAll({ DateTimeFormatValidationResults::HasHour, DateTimeFormatValidationResults::HasMinute });
+ return results.containsAll({ DateTimeFormatValidationResults::HasHour, DateTimeFormatValidationResults::HasMinute, DateTimeFormatValidationResults::HasMeridiem });
}
-String TimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState&) const
+String TimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState& state) const
{
- return emptyString();
+ if (!state.hour || !state.minute || !state.meridiem)
+ return emptyString();
+
+ unsigned hour23 = (*state.hour % 12) + (*state.meridiem == DateTimeFieldsState::Meridiem::PM ? 12 : 0);
+ auto hourMinuteString = makeString(pad('0', 2, hour23), ':', pad('0', 2, *state.minute));
+
+ if (state.millisecond)
+ return makeString(hourMinuteString, ':', pad('0', 2, state.second ? *state.second : 0), '.', pad('0', 3, *state.millisecond));
+
+ if (state.second)
+ return makeString(hourMinuteString, ':', pad('0', 2, *state.second));
+
+ return hourMinuteString;
}
-void TimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
+void TimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& date) const
{
+ auto stepRange = createStepRange(AnyStepHandling::Default);
+ auto millisecondsPerSecond = Decimal::fromDouble(msPerSecond);
+ auto millisecondsPerMinute = Decimal::fromDouble(msPerMinute);
+
+ layoutParameters.shouldHaveMillisecondField = date.millisecond()
+ || !stepRange.minimum().remainder(millisecondsPerSecond).isZero()
+ || !stepRange.step().remainder(millisecondsPerSecond).isZero();
+
+ bool shouldHaveSecondField = layoutParameters.shouldHaveMillisecondField
+ || date.second()
+ || !stepRange.minimum().remainder(millisecondsPerMinute).isZero()
+ || !stepRange.step().remainder(millisecondsPerMinute).isZero();
+
+ if (shouldHaveSecondField) {
+ layoutParameters.dateTimeFormat = layoutParameters.locale.timeFormat();
+ layoutParameters.fallbackDateTimeFormat = "HH:mm:ss"_s;
+ } else {
+ layoutParameters.dateTimeFormat = layoutParameters.locale.shortTimeFormat();
+ layoutParameters.fallbackDateTimeFormat = "HH:mm"_s;
+ }
}
} // namespace WebCore
Modified: trunk/Source/WebCore/html/TimeInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/TimeInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/TimeInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -52,7 +52,7 @@
bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
- void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
+ void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const final;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/WeekInputType.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/WeekInputType.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/WeekInputType.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -97,7 +97,7 @@
return emptyString();
}
-void WeekInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
+void WeekInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const
{
}
Modified: trunk/Source/WebCore/html/WeekInputType.h (266778 => 266779)
--- trunk/Source/WebCore/html/WeekInputType.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/WeekInputType.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -51,7 +51,7 @@
bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
- void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
+ void setupLayoutParameters(DateTimeEditElement::LayoutParameters&, const DateComponents&) const final;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/shadow/DateTimeEditElement.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeEditElement.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeEditElement.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -85,6 +85,36 @@
return;
}
+ case DateTimeFormat::FieldTypeFractionalSecond: {
+ m_editElement.addField(DateTimeMillisecondFieldElement::create(document, m_editElement));
+ return;
+ }
+
+ case DateTimeFormat::FieldTypeHour11: {
+ m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 0, 11));
+ return;
+ }
+
+ case DateTimeFormat::FieldTypeHour12: {
+ m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 1, 12));
+ return;
+ }
+
+ case DateTimeFormat::FieldTypeHour23: {
+ m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 0, 23));
+ return;
+ }
+
+ case DateTimeFormat::FieldTypeHour24: {
+ m_editElement.addField(DateTimeHourFieldElement::create(document, m_editElement, 1, 24));
+ return;
+ }
+
+ case DateTimeFormat::FieldTypeMinute: {
+ m_editElement.addField(DateTimeMinuteFieldElement::create(document, m_editElement));
+ return;
+ }
+
case DateTimeFormat::FieldTypeMonth:
case DateTimeFormat::FieldTypeMonthStandAlone: {
constexpr int countForAbbreviatedMonth = 3;
@@ -109,6 +139,21 @@
}
}
+ case DateTimeFormat::FieldTypePeriod: {
+ m_editElement.addField(DateTimeMeridiemFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels()));
+ return;
+ }
+
+ case DateTimeFormat::FieldTypeSecond: {
+ m_editElement.addField(DateTimeSecondFieldElement::create(document, m_editElement));
+
+ if (m_parameters.shouldHaveMillisecondField) {
+ visitLiteral(m_parameters.locale.localizedDecimalSeparator());
+ visitField(DateTimeFormat::FieldTypeFractionalSecond, 3);
+ }
+ return;
+ }
+
case DateTimeFormat::FieldTypeYear: {
m_editElement.addField(DateTimeYearFieldElement::create(document, m_editElement));
return;
Modified: trunk/Source/WebCore/html/shadow/DateTimeEditElement.h (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeEditElement.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeEditElement.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -55,6 +55,7 @@
String dateTimeFormat;
String fallbackDateTimeFormat;
Locale& locale;
+ bool shouldHaveMillisecondField { false };
LayoutParameters(Locale& locale)
: locale(locale)
Modified: trunk/Source/WebCore/html/shadow/DateTimeFieldElements.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeFieldElements.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeFieldElements.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -60,6 +60,145 @@
setValueAsInteger(date.monthDay());
}
+WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeHourFieldElement);
+
+DateTimeHourFieldElement::DateTimeHourFieldElement(Document& document, FieldOwner& fieldOwner, int minimum, int maximum)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(minimum, maximum), "--"_s)
+{
+ static MainThreadNeverDestroyed<const AtomString> hourPseudoId("-webkit-datetime-edit-hour-field", AtomString::ConstructFromLiteral);
+ initialize(hourPseudoId);
+}
+
+Ref<DateTimeHourFieldElement> DateTimeHourFieldElement::create(Document& document, FieldOwner& fieldOwner, int minimum, int maximum)
+{
+ return adoptRef(*new DateTimeHourFieldElement(document, fieldOwner, minimum, maximum));
+}
+
+void DateTimeHourFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
+{
+ if (!hasValue())
+ return;
+
+ int value = valueAsInteger();
+
+ switch (maximum()) {
+ case 11:
+ state.hour = value ?: 12;
+ return;
+ case 12:
+ state.hour = value;
+ return;
+ case 23:
+ state.hour = (value % 12) ?: 12;
+ state.meridiem = value >= 12 ? DateTimeFieldsState::Meridiem::PM : DateTimeFieldsState::Meridiem::AM;
+ return;
+ case 24:
+ if (value == 24) {
+ state.hour = 12;
+ state.meridiem = DateTimeFieldsState::Meridiem::AM;
+ return;
+ }
+ state.hour = (value % 12) ?: 12;
+ state.meridiem = value >= 12 ? DateTimeFieldsState::Meridiem::PM : DateTimeFieldsState::Meridiem::AM;
+ return;
+ }
+}
+
+void DateTimeHourFieldElement::setValueAsDate(const DateComponents& date)
+{
+ int hour = date.hour();
+
+ switch (maximum()) {
+ case 11:
+ setValueAsInteger(hour % 12);
+ return;
+ case 12:
+ setValueAsInteger((hour % 12) ?: 12);
+ return;
+ case 23:
+ setValueAsInteger(hour);
+ return;
+ case 24:
+ setValueAsInteger(hour + 1);
+ return;
+ }
+}
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMeridiemFieldElement);
+
+DateTimeMeridiemFieldElement::DateTimeMeridiemFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels)
+ : DateTimeSymbolicFieldElement(document, fieldOwner, labels)
+{
+ static MainThreadNeverDestroyed<const AtomString> meridiemPseudoId("-webkit-datetime-edit-meridiem-field", AtomString::ConstructFromLiteral);
+ initialize(meridiemPseudoId);
+}
+
+Ref<DateTimeMeridiemFieldElement> DateTimeMeridiemFieldElement::create(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels)
+{
+ return adoptRef(*new DateTimeMeridiemFieldElement(document, fieldOwner, labels));
+}
+
+void DateTimeMeridiemFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
+{
+ if (hasValue())
+ state.meridiem = valueAsInteger() ? DateTimeFieldsState::Meridiem::PM : DateTimeFieldsState::Meridiem::AM;
+}
+
+void DateTimeMeridiemFieldElement::setValueAsDate(const DateComponents& date)
+{
+ setValueAsInteger(date.hour() >= 12 ? 1 : 0);
+}
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMillisecondFieldElement);
+
+DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement(Document& document, FieldOwner& fieldOwner)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 999), "--"_s)
+{
+ static MainThreadNeverDestroyed<const AtomString> millisecondPseudoId("-webkit-datetime-edit-millisecond-field", AtomString::ConstructFromLiteral);
+ initialize(millisecondPseudoId);
+}
+
+Ref<DateTimeMillisecondFieldElement> DateTimeMillisecondFieldElement::create(Document& document, FieldOwner& fieldOwner)
+{
+ return adoptRef(*new DateTimeMillisecondFieldElement(document, fieldOwner));
+}
+
+void DateTimeMillisecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
+{
+ if (hasValue())
+ state.millisecond = valueAsInteger();
+}
+
+void DateTimeMillisecondFieldElement::setValueAsDate(const DateComponents& date)
+{
+ setValueAsInteger(date.millisecond());
+}
+
+WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMinuteFieldElement);
+
+DateTimeMinuteFieldElement::DateTimeMinuteFieldElement(Document& document, FieldOwner& fieldOwner)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 59), "--"_s)
+{
+ static MainThreadNeverDestroyed<const AtomString> minutePseudoId("-webkit-datetime-edit-minute-field", AtomString::ConstructFromLiteral);
+ initialize(minutePseudoId);
+}
+
+Ref<DateTimeMinuteFieldElement> DateTimeMinuteFieldElement::create(Document& document, FieldOwner& fieldOwner)
+{
+ return adoptRef(*new DateTimeMinuteFieldElement(document, fieldOwner));
+}
+
+void DateTimeMinuteFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
+{
+ if (hasValue())
+ state.minute = valueAsInteger();
+}
+
+void DateTimeMinuteFieldElement::setValueAsDate(const DateComponents& date)
+{
+ setValueAsInteger(date.minute());
+}
+
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMonthFieldElement);
DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document& document, FieldOwner& fieldOwner)
@@ -86,6 +225,31 @@
setValueAsInteger(date.month() + 1);
}
+WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeSecondFieldElement);
+
+DateTimeSecondFieldElement::DateTimeSecondFieldElement(Document& document, FieldOwner& fieldOwner)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 59), "--"_s)
+{
+ static MainThreadNeverDestroyed<const AtomString> secondPseudoId("-webkit-datetime-edit-second-field", AtomString::ConstructFromLiteral);
+ initialize(secondPseudoId);
+}
+
+Ref<DateTimeSecondFieldElement> DateTimeSecondFieldElement::create(Document& document, FieldOwner& fieldOwner)
+{
+ return adoptRef(*new DateTimeSecondFieldElement(document, fieldOwner));
+}
+
+void DateTimeSecondFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
+{
+ if (hasValue())
+ state.second = valueAsInteger();
+}
+
+void DateTimeSecondFieldElement::setValueAsDate(const DateComponents& date)
+{
+ setValueAsInteger(date.second());
+}
+
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeSymbolicMonthFieldElement);
DateTimeSymbolicMonthFieldElement::DateTimeSymbolicMonthFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels)
Modified: trunk/Source/WebCore/html/shadow/DateTimeFieldElements.h (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeFieldElements.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeFieldElements.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -47,6 +47,62 @@
void populateDateTimeFieldsState(DateTimeFieldsState&);
};
+class DateTimeHourFieldElement final : public DateTimeNumericFieldElement {
+ WTF_MAKE_ISO_ALLOCATED(DateTimeHourFieldElement);
+
+public:
+ static Ref<DateTimeHourFieldElement> create(Document&, FieldOwner&, int minimum, int maximum);
+
+private:
+ DateTimeHourFieldElement(Document&, FieldOwner&, int minimum, int maximum);
+
+ // DateTimeFieldElement functions:
+ virtual void populateDateTimeFieldsState(DateTimeFieldsState&);
+ virtual void setValueAsDate(const DateComponents&);
+};
+
+class DateTimeMeridiemFieldElement final : public DateTimeSymbolicFieldElement {
+ WTF_MAKE_ISO_ALLOCATED(DateTimeMeridiemFieldElement);
+
+public:
+ static Ref<DateTimeMeridiemFieldElement> create(Document&, FieldOwner&, const Vector<String>&);
+
+private:
+ DateTimeMeridiemFieldElement(Document&, FieldOwner&, const Vector<String>&);
+
+ // DateTimeFieldElement functions:
+ void populateDateTimeFieldsState(DateTimeFieldsState&);
+ void setValueAsDate(const DateComponents&);
+};
+
+class DateTimeMillisecondFieldElement final : public DateTimeNumericFieldElement {
+ WTF_MAKE_ISO_ALLOCATED(DateTimeMillisecondFieldElement);
+
+public:
+ static Ref<DateTimeMillisecondFieldElement> create(Document&, FieldOwner&);
+
+private:
+ DateTimeMillisecondFieldElement(Document&, FieldOwner&);
+
+ // DateTimeFieldElement functions:
+ virtual void populateDateTimeFieldsState(DateTimeFieldsState&);
+ virtual void setValueAsDate(const DateComponents&);
+};
+
+class DateTimeMinuteFieldElement final : public DateTimeNumericFieldElement {
+ WTF_MAKE_ISO_ALLOCATED(DateTimeMinuteFieldElement);
+
+public:
+ static Ref<DateTimeMinuteFieldElement> create(Document&, FieldOwner&);
+
+private:
+ DateTimeMinuteFieldElement(Document&, FieldOwner&);
+
+ // DateTimeFieldElement functions:
+ virtual void populateDateTimeFieldsState(DateTimeFieldsState&);
+ virtual void setValueAsDate(const DateComponents&);
+};
+
class DateTimeMonthFieldElement final : public DateTimeNumericFieldElement {
WTF_MAKE_ISO_ALLOCATED(DateTimeMonthFieldElement);
@@ -61,6 +117,20 @@
void populateDateTimeFieldsState(DateTimeFieldsState&);
};
+class DateTimeSecondFieldElement final : public DateTimeNumericFieldElement {
+ WTF_MAKE_ISO_ALLOCATED(DateTimeSecondFieldElement);
+
+public:
+ static Ref<DateTimeSecondFieldElement> create(Document&, FieldOwner&);
+
+private:
+ DateTimeSecondFieldElement(Document&, FieldOwner&);
+
+ // DateTimeFieldElement functions:
+ virtual void populateDateTimeFieldsState(DateTimeFieldsState&);
+ virtual void setValueAsDate(const DateComponents&);
+};
+
class DateTimeSymbolicMonthFieldElement final : public DateTimeSymbolicFieldElement {
WTF_MAKE_ISO_ALLOCATED(DateTimeSymbolicMonthFieldElement);
Modified: trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -57,6 +57,11 @@
{
}
+int DateTimeNumericFieldElement::maximum() const
+{
+ return m_range.maximum;
+}
+
String DateTimeNumericFieldElement::formatValue(int value) const
{
Locale& locale = localeForOwner();
Modified: trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -50,6 +50,8 @@
protected:
DateTimeNumericFieldElement(Document&, FieldOwner&, const Range&, const String& placeholder);
+ int maximum() const;
+
// DateTimeFieldElement functions:
bool hasValue() const final;
void initialize(const AtomString&);
Modified: trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -49,6 +49,7 @@
: DateTimeFieldElement(document, fieldOwner)
, m_symbols(symbols)
, m_visibleEmptyValue(makeVisibleEmptyValue(symbols))
+ , m_typeAhead(this)
{
ASSERT(!m_symbols.isEmpty());
}
@@ -111,11 +112,34 @@
return hasValue() ? m_symbols[m_selectedIndex] : visibleEmptyValue();
}
-void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent&)
+void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent& keyboardEvent)
{
- // FIXME: Implement after adding layout for <input type=time>.
+ if (keyboardEvent.type() != eventNames().keypressEvent)
+ return;
+
+ keyboardEvent.setDefaultHandled();
+
+ int index = m_typeAhead.handleEvent(&keyboardEvent, TypeAhead::MatchPrefix | TypeAhead::CycleFirstChar | TypeAhead::MatchIndex);
+ if (index < 0)
+ return;
+ setValueAsInteger(index, DispatchInputAndChangeEvents);
}
+int DateTimeSymbolicFieldElement::indexOfSelectedOption() const
+{
+ return m_selectedIndex;
+}
+
+int DateTimeSymbolicFieldElement::optionCount() const
+{
+ return m_symbols.size();
+}
+
+String DateTimeSymbolicFieldElement::optionAtIndex(int index) const
+{
+ return m_symbols[index];
+}
+
} // namespace WebCore
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
Modified: trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h (266778 => 266779)
--- trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -29,10 +29,11 @@
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
#include "DateTimeFieldElement.h"
+#include "TypeAhead.h"
namespace WebCore {
-class DateTimeSymbolicFieldElement : public DateTimeFieldElement {
+class DateTimeSymbolicFieldElement : public DateTimeFieldElement, public TypeAheadDataSource {
WTF_MAKE_ISO_ALLOCATED(DateTimeSymbolicFieldElement);
protected:
DateTimeSymbolicFieldElement(Document&, FieldOwner&, const Vector<String>&);
@@ -55,9 +56,15 @@
String visibleValue() const final;
void handleKeyboardEvent(KeyboardEvent&) final;
+ // TypeAheadDataSource functions:
+ int indexOfSelectedOption() const final;
+ int optionCount() const final;
+ String optionAtIndex(int index) const final;
+
const Vector<String> m_symbols;
const AtomString m_visibleEmptyValue;
+ TypeAhead m_typeAhead;
int m_selectedIndex { invalidIndex };
};
Modified: trunk/Source/WebCore/platform/text/PlatformLocale.cpp (266778 => 266779)
--- trunk/Source/WebCore/platform/text/PlatformLocale.cpp 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/platform/text/PlatformLocale.cpp 2020-09-09 14:48:26 UTC (rev 266779)
@@ -354,6 +354,12 @@
}
return builder.toString();
}
+
+String Locale::localizedDecimalSeparator()
+{
+ initializeLocaleData();
+ return m_decimalSymbols[DecimalSeparatorIndex];
+}
#endif
}
Modified: trunk/Source/WebCore/platform/text/PlatformLocale.h (266778 => 266779)
--- trunk/Source/WebCore/platform/text/PlatformLocale.h 2020-09-09 13:37:16 UTC (rev 266778)
+++ trunk/Source/WebCore/platform/text/PlatformLocale.h 2020-09-09 14:48:26 UTC (rev 266779)
@@ -108,6 +108,8 @@
// localized string of January, and the last item is a localized string of
// December. These strings should not be abbreviations.
virtual const Vector<String>& monthLabels() = 0;
+
+ String localizedDecimalSeparator();
#endif
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)