| Differences between
and this patch
- a/Source/WebCore/ChangeLog +140 lines
Lines 1-3 a/Source/WebCore/ChangeLog_sec1
1
2020-08-28  Aditya Keerthi  <akeerthi@apple.com>
2
3
        [macOS] Handle events for date inputs with editable components
4
        https://bugs.webkit.org/show_bug.cgi?id=215938
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        This patch adds actual editability to date inputs with editable
9
        components, as the individual components now respond to keyboard
10
        events. Number keys can be used to enter a day, month, or year. The
11
        left and right arrow keys, as well as the tab key, can be used to
12
        traverse the various components. Finally, the backspace and delete keys
13
        can be used to clear the value of a particular component.
14
15
        To match the behavior of NSDatePicker, a typeahead buffer with a
16
        timeout is used when editing. For example, entering "2" and "3" in
17
        immediate succession will result in a year of "0023", but a one second
18
        gap between the two characters will result in a year of "0003".
19
20
        Finally, this patch ensures that "focus", "blur", "input", and "change"
21
        events are dispatched appropriately.
22
23
        Tests: fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events.html
24
               fast/forms/date/date-editable-components/date-editable-components-keyboard-events.html
25
               fast/forms/date/date-editable-components/date-editable-components-mouse-events.html
26
27
        * Sources.txt:
28
        * WebCore.xcodeproj/project.pbxproj:
29
        * html/BaseChooserOnlyDateAndTimeInputType.cpp:
30
        (WebCore::BaseChooserOnlyDateAndTimeInputType::elementDidBlur):
31
32
        Only close the attached picker if editable components do not exist, as
33
        the picker is already closed by didBlurFromControl.
34
35
        (WebCore::BaseChooserOnlyDateAndTimeInputType::handleFocusEvent):
36
37
        Override this method so that any attempt to focus the date input
38
        element will focus the appropriate editable component.
39
40
        (WebCore::BaseChooserOnlyDateAndTimeInputType::hasCustomFocusLogic const):
41
42
        Override this method and return false if editable components are
43
        present so that the element can be a FocusScopeOwner. This is needed to
44
        be able to tab through individual components.
45
46
        (WebCore::BaseChooserOnlyDateAndTimeInputType::didBlurFromControl):
47
        (WebCore::BaseChooserOnlyDateAndTimeInputType::editControlValueChanged):
48
        * html/BaseChooserOnlyDateAndTimeInputType.h:
49
        * html/BaseDateAndTimeInputType.cpp:
50
        (WebCore::BaseDateAndTimeInputType::isKeyboardFocusable const): Date inputs should be keyboard focusable on all platforms.
51
        * html/BaseDateAndTimeInputType.h:
52
        * html/DateInputType.cpp:
53
        (WebCore::DateInputType::formatDateTimeFieldsState const): Serialize the state of the edit control into a valid HTML date string.
54
        * html/DateInputType.h:
55
        * html/DateTimeFieldsState.cpp: Added.
56
57
        DateTimeFieldsState is used to serialize and deserialize the contents of
58
        DateTimeEditElement. In the future, this class will also be used to
59
        save form state on forward/backward navigation.
60
61
        (WebCore::DateTimeFieldsState::DateTimeFieldsState):
62
        * html/DateTimeFieldsState.h: Added.
63
        (WebCore::DateTimeFieldsState::dayOfMonth const):
64
        (WebCore::DateTimeFieldsState::month const):
65
        (WebCore::DateTimeFieldsState::year const):
66
        (WebCore::DateTimeFieldsState::hasDayOfMonth const):
67
        (WebCore::DateTimeFieldsState::hasMonth const):
68
        (WebCore::DateTimeFieldsState::hasYear const):
69
        (WebCore::DateTimeFieldsState::setDayOfMonth):
70
        (WebCore::DateTimeFieldsState::setMonth):
71
        (WebCore::DateTimeFieldsState::setYear):
72
        * html/DateTimeLocalInputType.cpp:
73
        (WebCore::DateTimeLocalInputType::formatDateTimeFieldsState const):
74
        * html/DateTimeLocalInputType.h:
75
        * html/MonthInputType.cpp:
76
        (WebCore::MonthInputType::formatDateTimeFieldsState const):
77
        * html/MonthInputType.h:
78
        * html/TimeInputType.cpp:
79
        (WebCore::TimeInputType::formatDateTimeFieldsState const):
80
        * html/TimeInputType.h:
81
        * html/WeekInputType.cpp:
82
        (WebCore::WeekInputType::formatDateTimeFieldsState const):
83
        * html/WeekInputType.h:
84
        * html/shadow/DateTimeEditElement.cpp:
85
        (WebCore::DateTimeEditElement::fieldIndexOf const):
86
        (WebCore::DateTimeEditElement::blurFromField):
87
88
        If a field is blurred, ensure the owner is notified if none of the
89
        other fields are focused.
90
91
        (WebCore::DateTimeEditElement::fieldValueChanged):
92
        (WebCore::DateTimeEditElement::focusOnNextFocusableField):
93
        (WebCore::DateTimeEditElement::focusByOwner):
94
        (WebCore::DateTimeEditElement::focusOnNextField):
95
        (WebCore::DateTimeEditElement::focusOnPreviousField):
96
        (WebCore::DateTimeEditElement::value const):
97
        (WebCore::DateTimeEditElement::valueAsDateTimeFieldsState const):
98
        * html/shadow/DateTimeEditElement.h:
99
        * html/shadow/DateTimeFieldElement.cpp:
100
        (WebCore::DateTimeFieldElement::defaultEventHandler):
101
        (WebCore::DateTimeFieldElement::defaultKeyboardEventHandler):
102
        (WebCore::DateTimeFieldElement::dispatchBlurEvent):
103
        (WebCore::DateTimeFieldElement::didBlur):
104
        (WebCore::DateTimeFieldElement::updateVisibleValue): Add EventBehavior parameter to dispatch "input" and "change" events accordingly.
105
        * html/shadow/DateTimeFieldElement.h:
106
        * html/shadow/DateTimeFieldElements.cpp:
107
        (WebCore::DateTimeDayFieldElement::DateTimeDayFieldElement):
108
        (WebCore::DateTimeDayFieldElement::populateDateTimeFieldsState):
109
        (WebCore::DateTimeMonthFieldElement::DateTimeMonthFieldElement):
110
        (WebCore::DateTimeMonthFieldElement::populateDateTimeFieldsState):
111
        (WebCore::DateTimeSymbolicMonthFieldElement::populateDateTimeFieldsState):
112
        (WebCore::DateTimeYearFieldElement::DateTimeYearFieldElement):
113
        (WebCore::DateTimeYearFieldElement::populateDateTimeFieldsState):
114
        * html/shadow/DateTimeFieldElements.h:
115
        * html/shadow/DateTimeNumericFieldElement.cpp:
116
        (WebCore::DateTimeNumericFieldElement::Range::clampValue const):
117
        (WebCore::DateTimeNumericFieldElement::Range::isInRange const):
118
        (WebCore::DateTimeNumericFieldElement::DateTimeNumericFieldElement):
119
        (WebCore::DateTimeNumericFieldElement::formatValue const):
120
        (WebCore::DateTimeNumericFieldElement::setEmptyValue):
121
        (WebCore::DateTimeNumericFieldElement::setValueAsInteger):
122
        (WebCore::DateTimeNumericFieldElement::handleKeyboardEvent):
123
        (WebCore::DateTimeNumericFieldElement::didBlur):
124
        * html/shadow/DateTimeNumericFieldElement.h:
125
        (WebCore::DateTimeNumericFieldElement::Range::Range):
126
        * html/shadow/DateTimeSymbolicFieldElement.cpp:
127
        (WebCore::DateTimeSymbolicFieldElement::setEmptyValue):
128
        (WebCore::DateTimeSymbolicFieldElement::setValueAsInteger):
129
        (WebCore::DateTimeSymbolicFieldElement::handleKeyboardEvent):
130
        * html/shadow/DateTimeSymbolicFieldElement.h:
131
        * platform/DateComponents.cpp:
132
        (WebCore::DateComponents::parseYear):
133
        (WebCore::withinHTMLDateLimits):
134
        (WebCore::DateComponents::parseWeek):
135
        (WebCore::DateComponents::setMonthsSinceEpoch):
136
        (WebCore::DateComponents::setMillisecondsSinceEpochForWeek):
137
        * platform/DateComponents.h: Partial revert of changes made in r265126, to ensure the minimumYear and maximumYear are accessible.
138
        (WebCore::DateComponents::minimumYear):
139
        (WebCore::DateComponents::maximumYear):
140
1
2020-08-31  Wenson Hsieh  <wenson_hsieh@apple.com>
141
2020-08-31  Wenson Hsieh  <wenson_hsieh@apple.com>
2
142
3
        Optimize the implementation of TransformationMatrix::rotate(double)
143
        Optimize the implementation of TransformationMatrix::rotate(double)
- a/Source/WebCore/Sources.txt +1 lines
Lines 1079-1084 html/DOMTokenList.cpp a/Source/WebCore/Sources.txt_sec1
1079
html/DOMURL.cpp
1079
html/DOMURL.cpp
1080
html/DateInputType.cpp
1080
html/DateInputType.cpp
1081
html/DateTimeLocalInputType.cpp
1081
html/DateTimeLocalInputType.cpp
1082
html/DateTimeFieldsState.cpp
1082
html/DirectoryFileListCreator.cpp
1083
html/DirectoryFileListCreator.cpp
1083
html/EmailInputType.cpp
1084
html/EmailInputType.cpp
1084
html/EnterKeyHint.cpp
1085
html/EnterKeyHint.cpp
- a/Source/WebCore/WebCore.xcodeproj/project.pbxproj +6 lines
Lines 5079-5084 a/Source/WebCore/WebCore.xcodeproj/project.pbxproj_sec1
5079
		E4F9EEF3156DA00700D23E7E /* StyleSheetContents.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F9EEF1156D84C400D23E7E /* StyleSheetContents.h */; settings = {ATTRIBUTES = (Private, ); }; };
5079
		E4F9EEF3156DA00700D23E7E /* StyleSheetContents.h in Headers */ = {isa = PBXBuildFile; fileRef = E4F9EEF1156D84C400D23E7E /* StyleSheetContents.h */; settings = {ATTRIBUTES = (Private, ); }; };
5080
		E516699120FF9918009D2C27 /* ListButtonArrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E516698F20FF9916009D2C27 /* ListButtonArrow@2x.png */; };
5080
		E516699120FF9918009D2C27 /* ListButtonArrow@2x.png in Resources */ = {isa = PBXBuildFile; fileRef = E516698F20FF9916009D2C27 /* ListButtonArrow@2x.png */; };
5081
		E517670320B88C1400D41167 /* DataListSuggestionInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = E517670220B88C1400D41167 /* DataListSuggestionInformation.h */; settings = {ATTRIBUTES = (Private, ); }; };
5081
		E517670320B88C1400D41167 /* DataListSuggestionInformation.h in Headers */ = {isa = PBXBuildFile; fileRef = E517670220B88C1400D41167 /* DataListSuggestionInformation.h */; settings = {ATTRIBUTES = (Private, ); }; };
5082
		E51D6A1F24E1E25500891CFA /* DateTimeFieldsState.h in Headers */ = {isa = PBXBuildFile; fileRef = E51D6A1D24E1E25500891CFA /* DateTimeFieldsState.h */; };
5082
		E52CF54D20A268AC00DADA27 /* DataListSuggestionsClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E52CF54C20A268AC00DADA27 /* DataListSuggestionsClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
5083
		E52CF54D20A268AC00DADA27 /* DataListSuggestionsClient.h in Headers */ = {isa = PBXBuildFile; fileRef = E52CF54C20A268AC00DADA27 /* DataListSuggestionsClient.h */; settings = {ATTRIBUTES = (Private, ); }; };
5083
		E52CF54F20A35A2800DADA27 /* DataListSuggestionPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = E52CF54E20A35A2800DADA27 /* DataListSuggestionPicker.h */; settings = {ATTRIBUTES = (Private, ); }; };
5084
		E52CF54F20A35A2800DADA27 /* DataListSuggestionPicker.h in Headers */ = {isa = PBXBuildFile; fileRef = E52CF54E20A35A2800DADA27 /* DataListSuggestionPicker.h */; settings = {ATTRIBUTES = (Private, ); }; };
5084
		E52EFDF42112875A00AD282A /* InputMode.h in Headers */ = {isa = PBXBuildFile; fileRef = E52EFDF22112875A00AD282A /* InputMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
5085
		E52EFDF42112875A00AD282A /* InputMode.h in Headers */ = {isa = PBXBuildFile; fileRef = E52EFDF22112875A00AD282A /* InputMode.h */; settings = {ATTRIBUTES = (Private, ); }; };
Lines 15955-15960 a/Source/WebCore/WebCore.xcodeproj/project.pbxproj_sec2
15955
		E516698F20FF9916009D2C27 /* ListButtonArrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ListButtonArrow@2x.png"; sourceTree = "<group>"; };
15956
		E516698F20FF9916009D2C27 /* ListButtonArrow@2x.png */ = {isa = PBXFileReference; lastKnownFileType = image.png; path = "ListButtonArrow@2x.png"; sourceTree = "<group>"; };
15956
		E517670220B88C1400D41167 /* DataListSuggestionInformation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionInformation.h; sourceTree = "<group>"; };
15957
		E517670220B88C1400D41167 /* DataListSuggestionInformation.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionInformation.h; sourceTree = "<group>"; };
15957
		E51A81DE17298D7700BFCA61 /* JSPerformance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformance.cpp; sourceTree = "<group>"; };
15958
		E51A81DE17298D7700BFCA61 /* JSPerformance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = JSPerformance.cpp; sourceTree = "<group>"; };
15959
		E51D6A1D24E1E25500891CFA /* DateTimeFieldsState.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DateTimeFieldsState.h; sourceTree = "<group>"; };
15960
		E51D6A1E24E1E25500891CFA /* DateTimeFieldsState.cpp */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.cpp.cpp; path = DateTimeFieldsState.cpp; sourceTree = "<group>"; };
15958
		E526AF3E1727F8F200E41781 /* Performance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Performance.cpp; sourceTree = "<group>"; };
15961
		E526AF3E1727F8F200E41781 /* Performance.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = Performance.cpp; sourceTree = "<group>"; };
15959
		E52CF54C20A268AC00DADA27 /* DataListSuggestionsClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionsClient.h; sourceTree = "<group>"; };
15962
		E52CF54C20A268AC00DADA27 /* DataListSuggestionsClient.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionsClient.h; sourceTree = "<group>"; };
15960
		E52CF54E20A35A2800DADA27 /* DataListSuggestionPicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionPicker.h; sourceTree = "<group>"; };
15963
		E52CF54E20A35A2800DADA27 /* DataListSuggestionPicker.h */ = {isa = PBXFileReference; lastKnownFileType = sourcecode.c.h; path = DataListSuggestionPicker.h; sourceTree = "<group>"; };
Lines 22608-22613 a/Source/WebCore/WebCore.xcodeproj/project.pbxproj_sec3
22608
				E517670220B88C1400D41167 /* DataListSuggestionInformation.h */,
22611
				E517670220B88C1400D41167 /* DataListSuggestionInformation.h */,
22609
				F55B3D811251F12D003EF269 /* DateInputType.cpp */,
22612
				F55B3D811251F12D003EF269 /* DateInputType.cpp */,
22610
				F55B3D821251F12D003EF269 /* DateInputType.h */,
22613
				F55B3D821251F12D003EF269 /* DateInputType.h */,
22614
				E51D6A1E24E1E25500891CFA /* DateTimeFieldsState.cpp */,
22615
				E51D6A1D24E1E25500891CFA /* DateTimeFieldsState.h */,
22611
				F55B3D851251F12D003EF269 /* DateTimeLocalInputType.cpp */,
22616
				F55B3D851251F12D003EF269 /* DateTimeLocalInputType.cpp */,
22612
				F55B3D861251F12D003EF269 /* DateTimeLocalInputType.h */,
22617
				F55B3D861251F12D003EF269 /* DateTimeLocalInputType.h */,
22613
				835D54C11F4DE53400E60671 /* DirectoryFileListCreator.cpp */,
22618
				835D54C11F4DE53400E60671 /* DirectoryFileListCreator.cpp */,
Lines 30844-30849 a/Source/WebCore/WebCore.xcodeproj/project.pbxproj_sec4
30844
				E5F06AF724D4BB5600BBC4F8 /* DateTimeEditElement.h in Headers */,
30849
				E5F06AF724D4BB5600BBC4F8 /* DateTimeEditElement.h in Headers */,
30845
				E5F06AE724D4847B00BBC4F8 /* DateTimeFieldElement.h in Headers */,
30850
				E5F06AE724D4847B00BBC4F8 /* DateTimeFieldElement.h in Headers */,
30846
				E5F06AF324D4AAE400BBC4F8 /* DateTimeFieldElements.h in Headers */,
30851
				E5F06AF324D4AAE400BBC4F8 /* DateTimeFieldElements.h in Headers */,
30852
				E51D6A1F24E1E25500891CFA /* DateTimeFieldsState.h in Headers */,
30847
				453EB637159C570400001BB7 /* DateTimeFormat.h in Headers */,
30853
				453EB637159C570400001BB7 /* DateTimeFormat.h in Headers */,
30848
				F55B3DBA1251F12D003EF269 /* DateTimeLocalInputType.h in Headers */,
30854
				F55B3DBA1251F12D003EF269 /* DateTimeLocalInputType.h in Headers */,
30849
				E5F06AEB24D49BF700BBC4F8 /* DateTimeNumericFieldElement.h in Headers */,
30855
				E5F06AEB24D49BF700BBC4F8 /* DateTimeNumericFieldElement.h in Headers */,
- a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp -4 / +29 lines
Lines 32-37 a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp_sec1
32
#include "Chrome.h"
32
#include "Chrome.h"
33
#include "DateTimeChooserParameters.h"
33
#include "DateTimeChooserParameters.h"
34
#include "DateTimeFormat.h"
34
#include "DateTimeFormat.h"
35
#include "FocusController.h"
35
#include "HTMLDivElement.h"
36
#include "HTMLDivElement.h"
36
#include "HTMLInputElement.h"
37
#include "HTMLInputElement.h"
37
#include "Page.h"
38
#include "Page.h"
Lines 141-147 void BaseChooserOnlyDateAndTimeInputType::handleDOMActivateEvent(Event&) a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp_sec2
141
142
142
void BaseChooserOnlyDateAndTimeInputType::elementDidBlur()
143
void BaseChooserOnlyDateAndTimeInputType::elementDidBlur()
143
{
144
{
144
    closeDateTimeChooser();
145
    if (!m_dateTimeEditElement)
146
        closeDateTimeChooser();
145
}
147
}
146
148
147
bool BaseChooserOnlyDateAndTimeInputType::isPresentingAttachedView() const
149
bool BaseChooserOnlyDateAndTimeInputType::isPresentingAttachedView() const
Lines 248-253 void BaseChooserOnlyDateAndTimeInputType::handleKeyupEvent(KeyboardEvent& event) a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp_sec3
248
    BaseClickableWithKeyInputType::handleKeyupEvent(*this, event);
250
    BaseClickableWithKeyInputType::handleKeyupEvent(*this, event);
249
}
251
}
250
252
253
void BaseChooserOnlyDateAndTimeInputType::handleFocusEvent(Node* oldFocusedNode, FocusDirection direction)
254
{
255
    if (!m_dateTimeEditElement) {
256
        InputType::handleFocusEvent(oldFocusedNode, direction);
257
    } else if (direction == FocusDirectionBackward) {
258
        if (auto* page = element()->document().page())
259
            page->focusController().advanceFocus(direction, 0);
260
    } else
261
        m_dateTimeEditElement->focusByOwner();
262
}
263
251
bool BaseChooserOnlyDateAndTimeInputType::accessKeyAction(bool sendMouseEvents)
264
bool BaseChooserOnlyDateAndTimeInputType::accessKeyAction(bool sendMouseEvents)
252
{
265
{
253
    BaseDateAndTimeInputType::accessKeyAction(sendMouseEvents);
266
    BaseDateAndTimeInputType::accessKeyAction(sendMouseEvents);
Lines 261-266 bool BaseChooserOnlyDateAndTimeInputType::isMouseFocusable() const a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp_sec4
261
    return element()->isTextFormControlFocusable();
274
    return element()->isTextFormControlFocusable();
262
}
275
}
263
276
277
bool BaseChooserOnlyDateAndTimeInputType::hasCustomFocusLogic() const
278
{
279
    if (m_dateTimeEditElement)
280
        return false;
281
    return InputType::hasCustomFocusLogic();
282
}
283
264
void BaseChooserOnlyDateAndTimeInputType::attributeChanged(const QualifiedName& name)
284
void BaseChooserOnlyDateAndTimeInputType::attributeChanged(const QualifiedName& name)
265
{
285
{
266
    if (name == valueAttr) {
286
    if (name == valueAttr) {
Lines 272-281 void BaseChooserOnlyDateAndTimeInputType::attributeChanged(const QualifiedName& a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.cpp_sec5
272
    BaseDateAndTimeInputType::attributeChanged(name);
292
    BaseDateAndTimeInputType::attributeChanged(name);
273
}
293
}
274
294
275
String BaseChooserOnlyDateAndTimeInputType::valueForEditControl() const
295
void BaseChooserOnlyDateAndTimeInputType::didBlurFromControl()
276
{
296
{
277
    ASSERT(element());
297
    closeDateTimeChooser();
278
    return element()->value();
298
}
299
300
void BaseChooserOnlyDateAndTimeInputType::editControlValueChanged()
301
{
302
    String value = sanitizeValue(m_dateTimeEditElement->value());
303
    BaseDateAndTimeInputType::setValue(value, value != element()->value(), DispatchInputAndChangeEvent);
279
}
304
}
280
305
281
AtomString BaseChooserOnlyDateAndTimeInputType::localeIdentifier() const
306
AtomString BaseChooserOnlyDateAndTimeInputType::localeIdentifier() const
- a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.h -1 / +4 lines
Lines 63-69 private: a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.h_sec1
63
    void closeDateTimeChooser();
63
    void closeDateTimeChooser();
64
64
65
    // DateTimeEditElement::EditControlOwner functions:
65
    // DateTimeEditElement::EditControlOwner functions:
66
    String valueForEditControl() const final;
66
    void didBlurFromControl() final;
67
    void editControlValueChanged() final;
67
    AtomString localeIdentifier() const final;
68
    AtomString localeIdentifier() const final;
68
69
69
    // InputType functions:
70
    // InputType functions:
Lines 76-84 private: a/Source/WebCore/html/BaseChooserOnlyDateAndTimeInputType.h_sec2
76
    ShouldCallBaseEventHandler handleKeydownEvent(KeyboardEvent&) override;
77
    ShouldCallBaseEventHandler handleKeydownEvent(KeyboardEvent&) override;
77
    void handleKeypressEvent(KeyboardEvent&) override;
78
    void handleKeypressEvent(KeyboardEvent&) override;
78
    void handleKeyupEvent(KeyboardEvent&) override;
79
    void handleKeyupEvent(KeyboardEvent&) override;
80
    void handleFocusEvent(Node* oldFocusedNode, FocusDirection) override;
79
    bool accessKeyAction(bool sendMouseEvents) override;
81
    bool accessKeyAction(bool sendMouseEvents) override;
80
    bool isMouseFocusable() const override;
82
    bool isMouseFocusable() const override;
81
    bool isPresentingAttachedView() const final;
83
    bool isPresentingAttachedView() const final;
84
    bool hasCustomFocusLogic() const override;
82
    void attributeChanged(const QualifiedName&) override;
85
    void attributeChanged(const QualifiedName&) override;
83
86
84
    // DateTimeChooserClient functions:
87
    // DateTimeChooserClient functions:
- a/Source/WebCore/html/BaseDateAndTimeInputType.cpp -2 lines
Lines 184-196 bool BaseDateAndTimeInputType::valueMissing(const String& value) const a/Source/WebCore/html/BaseDateAndTimeInputType.cpp_sec1
184
    return element()->isRequired() && value.isEmpty();
184
    return element()->isRequired() && value.isEmpty();
185
}
185
}
186
186
187
#if PLATFORM(IOS_FAMILY)
188
bool BaseDateAndTimeInputType::isKeyboardFocusable(KeyboardEvent*) const
187
bool BaseDateAndTimeInputType::isKeyboardFocusable(KeyboardEvent*) const
189
{
188
{
190
    ASSERT(element());
189
    ASSERT(element());
191
    return !element()->isReadOnly() && element()->isTextFormControlFocusable();
190
    return !element()->isReadOnly() && element()->isTextFormControlFocusable();
192
}
191
}
193
#endif
194
192
195
} // namespace WebCore
193
} // namespace WebCore
196
#endif
194
#endif
- a/Source/WebCore/html/BaseDateAndTimeInputType.h -2 lines
Lines 50-58 protected: a/Source/WebCore/html/BaseDateAndTimeInputType.h_sec1
50
    String serializeWithComponents(const DateComponents&) const;
50
    String serializeWithComponents(const DateComponents&) const;
51
    String visibleValue() const override;
51
    String visibleValue() const override;
52
    void attributeChanged(const QualifiedName&) override;
52
    void attributeChanged(const QualifiedName&) override;
53
#if PLATFORM(IOS_FAMILY)
54
    bool isKeyboardFocusable(KeyboardEvent*) const override;
53
    bool isKeyboardFocusable(KeyboardEvent*) const override;
55
#endif
56
54
57
    virtual Optional<DateComponents> parseToDateComponents(const StringView&) const = 0;
55
    virtual Optional<DateComponents> parseToDateComponents(const StringView&) const = 0;
58
56
- a/Source/WebCore/html/DateInputType.cpp +9 lines
Lines 33-38 a/Source/WebCore/html/DateInputType.cpp_sec1
33
#include "DateInputType.h"
33
#include "DateInputType.h"
34
34
35
#include "DateComponents.h"
35
#include "DateComponents.h"
36
#include "DateTimeFieldsState.h"
36
#include "HTMLInputElement.h"
37
#include "HTMLInputElement.h"
37
#include "HTMLNames.h"
38
#include "HTMLNames.h"
38
#include "InputTypeNames.h"
39
#include "InputTypeNames.h"
Lines 93-98 bool DateInputType::isValidFormat(OptionSet<DateTimeFormatValidationResults> res a/Source/WebCore/html/DateInputType.cpp_sec2
93
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasMonth, DateTimeFormatValidationResults::HasDay });
94
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasMonth, DateTimeFormatValidationResults::HasDay });
94
}
95
}
95
96
97
String DateInputType::formatDateTimeFieldsState(const DateTimeFieldsState& state) const
98
{
99
    if (!state.hasDayOfMonth() || !state.hasMonth() || !state.hasYear())
100
        return emptyString();
101
102
    return makeString(pad('0', 4, state.year()), '-', pad('0', 2, state.month()), '-', pad('0', 2, state.dayOfMonth()));
103
}
104
96
void DateInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters) const
105
void DateInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters& layoutParameters) const
97
{
106
{
98
    layoutParameters.dateTimeFormat = layoutParameters.locale.dateFormat();
107
    layoutParameters.dateTimeFormat = layoutParameters.locale.dateFormat();
- a/Source/WebCore/html/DateInputType.h +1 lines
Lines 49-54 private: a/Source/WebCore/html/DateInputType.h_sec1
49
    bool isDateField() const override;
49
    bool isDateField() const override;
50
50
51
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
51
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
52
    String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
52
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
53
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
53
};
54
};
54
55
- a/Source/WebCore/html/DateTimeFieldsState.cpp +45 lines
Line 0 a/Source/WebCore/html/DateTimeFieldsState.cpp_sec1
1
/*
2
 * Copyright (C) 2012 Google Inc. All rights reserved.
3
 * Copyright (C) 2020 Apple Inc. All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24
 * THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#include "config.h"
28
#include "DateTimeFieldsState.h"
29
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
31
32
namespace WebCore {
33
34
constexpr unsigned DateTimeFieldsState::emptyValue = static_cast<unsigned>(-1);
35
36
DateTimeFieldsState::DateTimeFieldsState()
37
    : m_year(emptyValue)
38
    , m_month(emptyValue)
39
    , m_dayOfMonth(emptyValue)
40
{
41
}
42
43
} // namespace WebCore
44
45
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
- a/Source/WebCore/html/DateTimeFieldsState.h +60 lines
Line 0 a/Source/WebCore/html/DateTimeFieldsState.h_sec1
1
/*
2
 * Copyright (C) 2012 Google Inc. All rights reserved.
3
 * Copyright (C) 2020 Apple Inc. All rights reserved.
4
 *
5
 * Redistribution and use in source and binary forms, with or without
6
 * modification, are permitted provided that the following conditions
7
 * are met:
8
 * 1. Redistributions of source code must retain the above copyright
9
 *    notice, this list of conditions and the following disclaimer.
10
 * 2. Redistributions in binary form must reproduce the above copyright
11
 *    notice, this list of conditions and the following disclaimer in the
12
 *    documentation and/or other materials provided with the distribution.
13
 *
14
 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS''
15
 * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO,
16
 * THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
17
 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS
18
 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
19
 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
20
 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
21
 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
22
 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
23
 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF
24
 * THE POSSIBILITY OF SUCH DAMAGE.
25
 */
26
27
#pragma once
28
29
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
30
31
namespace WebCore {
32
33
class DateTimeFieldsState {
34
public:
35
    static const unsigned emptyValue;
36
37
    DateTimeFieldsState();
38
39
    unsigned dayOfMonth() const { return m_dayOfMonth; }
40
    unsigned month() const { return m_month; }
41
    unsigned year() const { return m_year; }
42
43
    bool hasDayOfMonth() const { return m_dayOfMonth != emptyValue; }
44
    bool hasMonth() const { return m_month != emptyValue; }
45
    bool hasYear() const { return m_year != emptyValue; }
46
47
    void setDayOfMonth(unsigned dayOfMonth) { m_dayOfMonth = dayOfMonth; }
48
    void setMonth(unsigned month) { m_month = month; }
49
    void setYear(unsigned year) { m_year = year; }
50
51
private:
52
    unsigned m_year;
53
    unsigned m_month;
54
    unsigned m_dayOfMonth;
55
56
};
57
58
} // namespace WebCore
59
60
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
- a/Source/WebCore/html/DateTimeLocalInputType.cpp +5 lines
Lines 101-106 bool DateTimeLocalInputType::isValidFormat(OptionSet<DateTimeFormatValidationRes a/Source/WebCore/html/DateTimeLocalInputType.cpp_sec1
101
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasMonth, DateTimeFormatValidationResults::HasDay, DateTimeFormatValidationResults::HasHour, DateTimeFormatValidationResults::HasMinute });
101
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasMonth, DateTimeFormatValidationResults::HasDay, DateTimeFormatValidationResults::HasHour, DateTimeFormatValidationResults::HasMinute });
102
}
102
}
103
103
104
String DateTimeLocalInputType::formatDateTimeFieldsState(const DateTimeFieldsState&) const
105
{
106
    return emptyString();
107
}
108
104
void DateTimeLocalInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
109
void DateTimeLocalInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
105
{
110
{
106
}
111
}
- a/Source/WebCore/html/DateTimeLocalInputType.h +1 lines
Lines 51-56 private: a/Source/WebCore/html/DateTimeLocalInputType.h_sec1
51
    bool isDateTimeLocalField() const final;
51
    bool isDateTimeLocalField() const final;
52
52
53
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
53
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
54
    String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
54
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
55
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
55
};
56
};
56
57
- a/Source/WebCore/html/MonthInputType.cpp +5 lines
Lines 139-144 bool MonthInputType::isValidFormat(OptionSet<DateTimeFormatValidationResults> re a/Source/WebCore/html/MonthInputType.cpp_sec1
139
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasMonth });
139
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasMonth });
140
}
140
}
141
141
142
String MonthInputType::formatDateTimeFieldsState(const DateTimeFieldsState&) const
143
{
144
    return emptyString();
145
}
146
142
void MonthInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
147
void MonthInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
143
{
148
{
144
}
149
}
- a/Source/WebCore/html/MonthInputType.h +1 lines
Lines 54-59 private: a/Source/WebCore/html/MonthInputType.h_sec1
54
    void handleDOMActivateEvent(Event&) override;
54
    void handleDOMActivateEvent(Event&) override;
55
55
56
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
56
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
57
    String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
57
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
58
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
58
};
59
};
59
60
- a/Source/WebCore/html/TimeInputType.cpp +5 lines
Lines 115-120 bool TimeInputType::isValidFormat(OptionSet<DateTimeFormatValidationResults> res a/Source/WebCore/html/TimeInputType.cpp_sec1
115
    return results.containsAll({ DateTimeFormatValidationResults::HasHour, DateTimeFormatValidationResults::HasMinute });
115
    return results.containsAll({ DateTimeFormatValidationResults::HasHour, DateTimeFormatValidationResults::HasMinute });
116
}
116
}
117
117
118
String TimeInputType::formatDateTimeFieldsState(const DateTimeFieldsState&) const
119
{
120
    return emptyString();
121
}
122
118
void TimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
123
void TimeInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
119
{
124
{
120
}
125
}
- a/Source/WebCore/html/TimeInputType.h +1 lines
Lines 51-56 private: a/Source/WebCore/html/TimeInputType.h_sec1
51
    void handleDOMActivateEvent(Event&) override;
51
    void handleDOMActivateEvent(Event&) override;
52
52
53
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
53
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
54
    String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
54
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
55
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
55
};
56
};
56
57
- a/Source/WebCore/html/WeekInputType.cpp +5 lines
Lines 92-97 bool WeekInputType::isValidFormat(OptionSet<DateTimeFormatValidationResults> res a/Source/WebCore/html/WeekInputType.cpp_sec1
92
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasWeek });
92
    return results.containsAll({ DateTimeFormatValidationResults::HasYear, DateTimeFormatValidationResults::HasWeek });
93
}
93
}
94
94
95
String WeekInputType::formatDateTimeFieldsState(const DateTimeFieldsState&) const
96
{
97
    return emptyString();
98
}
99
95
void WeekInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
100
void WeekInputType::setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const
96
{
101
{
97
}
102
}
- a/Source/WebCore/html/WeekInputType.h +1 lines
Lines 50-55 private: a/Source/WebCore/html/WeekInputType.h_sec1
50
    void handleDOMActivateEvent(Event&) override;
50
    void handleDOMActivateEvent(Event&) override;
51
51
52
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
52
    bool isValidFormat(OptionSet<DateTimeFormatValidationResults>) const final;
53
    String formatDateTimeFieldsState(const DateTimeFieldsState&) const final;
53
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
54
    void setupLayoutParameters(DateTimeEditElement::LayoutParameters&) const final;
54
};
55
};
55
56
- a/Source/WebCore/html/shadow/DateTimeEditElement.cpp -1 / +83 lines
Lines 31-36 a/Source/WebCore/html/shadow/DateTimeEditElement.cpp_sec1
31
31
32
#include "DateComponents.h"
32
#include "DateComponents.h"
33
#include "DateTimeFieldElements.h"
33
#include "DateTimeFieldElements.h"
34
#include "DateTimeFieldsState.h"
34
#include "DateTimeFormat.h"
35
#include "DateTimeFormat.h"
35
#include "DateTimeSymbolicFieldElement.h"
36
#include "DateTimeSymbolicFieldElement.h"
36
#include "HTMLNames.h"
37
#include "HTMLNames.h"
Lines 154-159 void DateTimeEditElement::addField(Ref<DateTimeFieldElement> field) a/Source/WebCore/html/shadow/DateTimeEditElement.cpp_sec2
154
    fieldsWrapperElement().appendChild(field);
155
    fieldsWrapperElement().appendChild(field);
155
}
156
}
156
157
158
size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const
159
{
160
    for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
161
        if (m_fields[fieldIndex].ptr() == &field)
162
            return fieldIndex;
163
    }
164
    return invalidFieldIndex;
165
}
166
157
Ref<DateTimeEditElement> DateTimeEditElement::create(Document& document, EditControlOwner& editControlOwner)
167
Ref<DateTimeEditElement> DateTimeEditElement::create(Document& document, EditControlOwner& editControlOwner)
158
{
168
{
159
    return adoptRef(*new DateTimeEditElement(document, editControlOwner));
169
    return adoptRef(*new DateTimeEditElement(document, editControlOwner));
Lines 187-192 void DateTimeEditElement::layout(const LayoutParameters& layoutParameters) a/Source/WebCore/html/shadow/DateTimeEditElement.cpp_sec3
187
    }
197
    }
188
}
198
}
189
199
200
void DateTimeEditElement::blurFromField(RefPtr<Element>&& newFocusedElement)
201
{
202
    bool notifyOwner = true;
203
    for (auto& field : m_fields) {
204
        if (field.ptr() == newFocusedElement.get()) {
205
            notifyOwner = false;
206
            break;
207
        }
208
    }
209
210
    HTMLElement::dispatchBlurEvent(WTFMove(newFocusedElement));
211
212
    if (m_editControlOwner && notifyOwner)
213
        m_editControlOwner->didBlurFromControl();
214
}
215
216
void DateTimeEditElement::fieldValueChanged()
217
{
218
    if (m_editControlOwner)
219
        m_editControlOwner->editControlValueChanged();
220
}
221
222
bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex)
223
{
224
    for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) {
225
        if (m_fields[fieldIndex]->isFocusable()) {
226
            m_fields[fieldIndex]->focus();
227
            return true;
228
        }
229
    }
230
    return false;
231
}
232
233
void DateTimeEditElement::focusByOwner()
234
{
235
    focusOnNextFocusableField(0);
236
}
237
238
bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field)
239
{
240
    const size_t startFieldIndex = fieldIndexOf(field);
241
    if (startFieldIndex == invalidFieldIndex)
242
        return false;
243
    return focusOnNextFocusableField(startFieldIndex + 1);
244
}
245
246
bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field)
247
{
248
    const size_t startFieldIndex = fieldIndexOf(field);
249
    if (startFieldIndex == invalidFieldIndex)
250
        return false;
251
252
    size_t fieldIndex = startFieldIndex;
253
    while (fieldIndex > 0) {
254
        --fieldIndex;
255
        if (m_fields[fieldIndex]->isFocusable()) {
256
            m_fields[fieldIndex]->focus();
257
            return true;
258
        }
259
    }
260
261
    return false;
262
}
263
190
AtomString DateTimeEditElement::localeIdentifier() const
264
AtomString DateTimeEditElement::localeIdentifier() const
191
{
265
{
192
    return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom();
266
    return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom();
Lines 213-219 void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters a/Source/WebCore/html/shadow/DateTimeEditElement.cpp_sec4
213
287
214
String DateTimeEditElement::value() const
288
String DateTimeEditElement::value() const
215
{
289
{
216
    return m_editControlOwner ? m_editControlOwner->valueForEditControl() : emptyString();
290
    return m_editControlOwner ? m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState()) : emptyString();
291
}
292
293
DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const
294
{
295
    DateTimeFieldsState dateTimeFieldsState;
296
    for (auto& field : m_fields)
297
        field->populateDateTimeFieldsState(dateTimeFieldsState);
298
    return dateTimeFieldsState;
217
}
299
}
218
300
219
} // namespace WebCore
301
} // namespace WebCore
- a/Source/WebCore/html/shadow/DateTimeEditElement.h -1 / +14 lines
Lines 43-49 public: a/Source/WebCore/html/shadow/DateTimeEditElement.h_sec1
43
    class EditControlOwner : public CanMakeWeakPtr<EditControlOwner> {
43
    class EditControlOwner : public CanMakeWeakPtr<EditControlOwner> {
44
    public:
44
    public:
45
        virtual ~EditControlOwner();
45
        virtual ~EditControlOwner();
46
        virtual String valueForEditControl() const = 0;
46
        virtual void didBlurFromControl() = 0;
47
        virtual void editControlValueChanged() = 0;
48
        virtual String formatDateTimeFieldsState(const DateTimeFieldsState&) const = 0;
47
        virtual AtomString localeIdentifier() const = 0;
49
        virtual AtomString localeIdentifier() const = 0;
48
    };
50
    };
49
51
Lines 63-74 public: a/Source/WebCore/html/shadow/DateTimeEditElement.h_sec2
63
    virtual ~DateTimeEditElement();
65
    virtual ~DateTimeEditElement();
64
    void addField(Ref<DateTimeFieldElement>);
66
    void addField(Ref<DateTimeFieldElement>);
65
    Element& fieldsWrapperElement() const;
67
    Element& fieldsWrapperElement() const;
68
    void focusByOwner();
66
    void resetFields();
69
    void resetFields();
67
    void setEmptyValue(const LayoutParameters&);
70
    void setEmptyValue(const LayoutParameters&);
68
    void setValueAsDate(const LayoutParameters&, const DateComponents&);
71
    void setValueAsDate(const LayoutParameters&, const DateComponents&);
69
    String value() const;
72
    String value() const;
70
73
71
private:
74
private:
75
    static constexpr size_t invalidFieldIndex = static_cast<size_t>(-1);
76
72
    // Datetime can be represented by at most 8 fields:
77
    // Datetime can be represented by at most 8 fields:
73
    // 1. year
78
    // 1. year
74
    // 2. month
79
    // 2. month
Lines 82-90 private: a/Source/WebCore/html/shadow/DateTimeEditElement.h_sec3
82
87
83
    DateTimeEditElement(Document&, EditControlOwner&);
88
    DateTimeEditElement(Document&, EditControlOwner&);
84
89
90
    size_t fieldIndexOf(const DateTimeFieldElement&) const;
85
    void layout(const LayoutParameters&);
91
    void layout(const LayoutParameters&);
92
    DateTimeFieldsState valueAsDateTimeFieldsState() const;
93
94
    bool focusOnNextFocusableField(size_t startIndex);
86
95
87
    // DateTimeFieldElement::FieldOwner functions:
96
    // DateTimeFieldElement::FieldOwner functions:
97
    void blurFromField(RefPtr<Element>&& newFocusedElement) final;
98
    void fieldValueChanged() final;
99
    bool focusOnNextField(const DateTimeFieldElement&) final;
100
    bool focusOnPreviousField(const DateTimeFieldElement&) final;
88
    AtomString localeIdentifier() const final;
101
    AtomString localeIdentifier() const final;
89
102
90
    Vector<Ref<DateTimeFieldElement>, maximumNumberOfFields> m_fields;
103
    Vector<Ref<DateTimeFieldElement>, maximumNumberOfFields> m_fields;
- a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp -1 / +64 lines
Lines 30-36 a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp_sec1
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
31
31
32
#include "DateComponents.h"
32
#include "DateComponents.h"
33
#include "EventNames.h"
33
#include "HTMLNames.h"
34
#include "HTMLNames.h"
35
#include "KeyboardEvent.h"
34
#include "LocalizedStrings.h"
36
#include "LocalizedStrings.h"
35
#include "PlatformLocale.h"
37
#include "PlatformLocale.h"
36
#include "Text.h"
38
#include "Text.h"
Lines 55-60 void DateTimeFieldElement::initialize(const AtomString& pseudo) a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp_sec2
55
    setPseudo(pseudo);
57
    setPseudo(pseudo);
56
}
58
}
57
59
60
void DateTimeFieldElement::defaultEventHandler(Event& event)
61
{
62
    if (is<KeyboardEvent>(event)) {
63
        auto& keyboardEvent = downcast<KeyboardEvent>(event);
64
        handleKeyboardEvent(keyboardEvent);
65
        if (keyboardEvent.defaultHandled())
66
            return;
67
        defaultKeyboardEventHandler(keyboardEvent);
68
        if (keyboardEvent.defaultHandled())
69
            return;
70
    }
71
72
    HTMLDivElement::defaultEventHandler(event);
73
}
74
75
void DateTimeFieldElement::defaultKeyboardEventHandler(KeyboardEvent& keyboardEvent)
76
{
77
    if (keyboardEvent.type() != eventNames().keydownEvent)
78
        return;
79
80
    auto key = keyboardEvent.keyIdentifier();
81
82
    if (key == "Left") {
83
        if (m_fieldOwner && m_fieldOwner->focusOnPreviousField(*this)) {
84
            keyboardEvent.setDefaultHandled();
85
            return;
86
        }
87
    }
88
89
    if (key == "Right") {
90
        if (m_fieldOwner && m_fieldOwner->focusOnNextField(*this)) {
91
            keyboardEvent.setDefaultHandled();
92
            return;
93
        }
94
    }
95
96
    // Clear value when pressing backspace or delete.
97
    if (key == "U+0008" || key == "U+007F") {
98
        keyboardEvent.setDefaultHandled();
99
        setEmptyValue(DispatchInputAndChangeEvent);
100
        return;
101
    }
102
}
103
104
void DateTimeFieldElement::dispatchBlurEvent(RefPtr<Element>&& newFocusedElement)
105
{
106
    if (m_fieldOwner)
107
        m_fieldOwner->blurFromField(WTFMove(newFocusedElement));
108
    else
109
        HTMLElement::dispatchBlurEvent(WTFMove(newFocusedElement));
110
111
    didBlur();
112
}
113
114
void DateTimeFieldElement::didBlur()
115
{
116
}
117
58
Locale& DateTimeFieldElement::localeForOwner() const
118
Locale& DateTimeFieldElement::localeForOwner() const
59
{
119
{
60
    return document().getCachedLocale(localeIdentifier());
120
    return document().getCachedLocale(localeIdentifier());
Lines 65-71 AtomString DateTimeFieldElement::localeIdentifier() const a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp_sec3
65
    return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom();
125
    return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom();
66
}
126
}
67
127
68
void DateTimeFieldElement::updateVisibleValue()
128
void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior)
69
{
129
{
70
    if (!firstChild())
130
    if (!firstChild())
71
        appendChild(Text::create(document(), emptyString()));
131
        appendChild(Text::create(document(), emptyString()));
Lines 76-81 void DateTimeFieldElement::updateVisibleValue() a/Source/WebCore/html/shadow/DateTimeFieldElement.cpp_sec4
76
        return;
136
        return;
77
137
78
    textNode.replaceWholeText(newVisibleValue);
138
    textNode.replaceWholeText(newVisibleValue);
139
140
    if (eventBehavior == DispatchInputAndChangeEvent && m_fieldOwner)
141
        m_fieldOwner->fieldValueChanged();
79
}
142
}
80
143
81
bool DateTimeFieldElement::supportsFocus() const
144
bool DateTimeFieldElement::supportsFocus() const
- a/Source/WebCore/html/shadow/DateTimeFieldElement.h -3 / +19 lines
Lines 35-54 a/Source/WebCore/html/shadow/DateTimeFieldElement.h_sec1
35
namespace WebCore {
35
namespace WebCore {
36
36
37
class DateComponents;
37
class DateComponents;
38
class DateTimeFieldsState;
38
39
39
class DateTimeFieldElement : public HTMLDivElement {
40
class DateTimeFieldElement : public HTMLDivElement {
40
    WTF_MAKE_ISO_ALLOCATED(DateTimeFieldElement);
41
    WTF_MAKE_ISO_ALLOCATED(DateTimeFieldElement);
41
public:
42
public:
43
    enum EventBehavior { DispatchNoEvent, DispatchInputAndChangeEvent };
44
42
    class FieldOwner : public CanMakeWeakPtr<FieldOwner> {
45
    class FieldOwner : public CanMakeWeakPtr<FieldOwner> {
43
    public:
46
    public:
44
        virtual ~FieldOwner();
47
        virtual ~FieldOwner();
48
        virtual void blurFromField(RefPtr<Element>&& newFocusedElement) = 0;
49
        virtual void fieldValueChanged() = 0;
50
        virtual bool focusOnNextField(const DateTimeFieldElement&) = 0;
51
        virtual bool focusOnPreviousField(const DateTimeFieldElement&) = 0;
45
        virtual AtomString localeIdentifier() const = 0;
52
        virtual AtomString localeIdentifier() const = 0;
46
    };
53
    };
47
54
55
    void defaultEventHandler(Event&) override;
56
    void dispatchBlurEvent(RefPtr<Element>&& newFocusedElement) override;
57
48
    virtual bool hasValue() const = 0;
58
    virtual bool hasValue() const = 0;
49
    virtual void setEmptyValue() = 0;
59
    virtual void populateDateTimeFieldsState(DateTimeFieldsState&) = 0;
60
    virtual void setEmptyValue(EventBehavior = DispatchNoEvent) = 0;
50
    virtual void setValueAsDate(const DateComponents&) = 0;
61
    virtual void setValueAsDate(const DateComponents&) = 0;
51
    virtual void setValueAsInteger(int) = 0;
62
    virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) = 0;
52
    virtual String value() const = 0;
63
    virtual String value() const = 0;
53
    virtual String visibleValue() const = 0;
64
    virtual String visibleValue() const = 0;
54
65
Lines 57-68 protected: a/Source/WebCore/html/shadow/DateTimeFieldElement.h_sec2
57
    void initialize(const AtomString& pseudo);
68
    void initialize(const AtomString& pseudo);
58
    Locale& localeForOwner() const;
69
    Locale& localeForOwner() const;
59
    AtomString localeIdentifier() const;
70
    AtomString localeIdentifier() const;
60
    void updateVisibleValue();
71
    void updateVisibleValue(EventBehavior);
61
    virtual int valueAsInteger() const = 0;
72
    virtual int valueAsInteger() const = 0;
73
    virtual void handleKeyboardEvent(KeyboardEvent&) = 0;
74
75
    virtual void didBlur();
62
76
63
private:
77
private:
64
    bool supportsFocus() const override;
78
    bool supportsFocus() const override;
65
79
80
    void defaultKeyboardEventHandler(KeyboardEvent&);
81
66
    WeakPtr<FieldOwner> m_fieldOwner;
82
    WeakPtr<FieldOwner> m_fieldOwner;
67
};
83
};
68
84
- a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp -3 / +24 lines
Lines 30-35 a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec1
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
31
31
32
#include "DateComponents.h"
32
#include "DateComponents.h"
33
#include "DateTimeFieldsState.h"
33
#include <wtf/IsoMallocInlines.h>
34
#include <wtf/IsoMallocInlines.h>
34
35
35
namespace WebCore {
36
namespace WebCore {
Lines 37-43 namespace WebCore { a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec2
37
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeDayFieldElement);
38
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeDayFieldElement);
38
39
39
DateTimeDayFieldElement::DateTimeDayFieldElement(Document& document, FieldOwner& fieldOwner)
40
DateTimeDayFieldElement::DateTimeDayFieldElement(Document& document, FieldOwner& fieldOwner)
40
    : DateTimeNumericFieldElement(document, fieldOwner, "--"_s)
41
    : DateTimeNumericFieldElement(document, fieldOwner, Range(1, 31), "--"_s)
41
{
42
{
42
    static MainThreadNeverDestroyed<const AtomString> dayPseudoId("-webkit-datetime-edit-day-field", AtomString::ConstructFromLiteral);
43
    static MainThreadNeverDestroyed<const AtomString> dayPseudoId("-webkit-datetime-edit-day-field", AtomString::ConstructFromLiteral);
43
    initialize(dayPseudoId);
44
    initialize(dayPseudoId);
Lines 48-53 Ref<DateTimeDayFieldElement> DateTimeDayFieldElement::create(Document& document, a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec3
48
    return adoptRef(*new DateTimeDayFieldElement(document, fieldOwner));
49
    return adoptRef(*new DateTimeDayFieldElement(document, fieldOwner));
49
}
50
}
50
51
52
void DateTimeDayFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
53
{
54
    state.setDayOfMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
55
}
56
51
void DateTimeDayFieldElement::setValueAsDate(const DateComponents& date)
57
void DateTimeDayFieldElement::setValueAsDate(const DateComponents& date)
52
{
58
{
53
    setValueAsInteger(date.monthDay());
59
    setValueAsInteger(date.monthDay());
Lines 56-62 void DateTimeDayFieldElement::setValueAsDate(const DateComponents& date) a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec4
56
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMonthFieldElement);
62
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMonthFieldElement);
57
63
58
DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document& document, FieldOwner& fieldOwner)
64
DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document& document, FieldOwner& fieldOwner)
59
    : DateTimeNumericFieldElement(document, fieldOwner, "--"_s)
65
    : DateTimeNumericFieldElement(document, fieldOwner, Range(1, 12), "--"_s)
60
{
66
{
61
    static MainThreadNeverDestroyed<const AtomString> monthPseudoId("-webkit-datetime-edit-month-field", AtomString::ConstructFromLiteral);
67
    static MainThreadNeverDestroyed<const AtomString> monthPseudoId("-webkit-datetime-edit-month-field", AtomString::ConstructFromLiteral);
62
    initialize(monthPseudoId);
68
    initialize(monthPseudoId);
Lines 67-72 Ref<DateTimeMonthFieldElement> DateTimeMonthFieldElement::create(Document& docum a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec5
67
    return adoptRef(*new DateTimeMonthFieldElement(document, fieldOwner));
73
    return adoptRef(*new DateTimeMonthFieldElement(document, fieldOwner));
68
}
74
}
69
75
76
void DateTimeMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
77
{
78
    state.setMonth(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
79
}
80
70
void DateTimeMonthFieldElement::setValueAsDate(const DateComponents& date)
81
void DateTimeMonthFieldElement::setValueAsDate(const DateComponents& date)
71
{
82
{
72
    // DateComponents represents months from 0 (January) to 11 (December).
83
    // DateComponents represents months from 0 (January) to 11 (December).
Lines 87-92 Ref<DateTimeSymbolicMonthFieldElement> DateTimeSymbolicMonthFieldElement::create a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec6
87
    return adoptRef(*new DateTimeSymbolicMonthFieldElement(document, fieldOwner, labels));
98
    return adoptRef(*new DateTimeSymbolicMonthFieldElement(document, fieldOwner, labels));
88
}
99
}
89
100
101
void DateTimeSymbolicMonthFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
102
{
103
    state.setMonth(hasValue() ? valueAsInteger() + 1 : DateTimeFieldsState::emptyValue);
104
}
105
90
void DateTimeSymbolicMonthFieldElement::setValueAsDate(const DateComponents& date)
106
void DateTimeSymbolicMonthFieldElement::setValueAsDate(const DateComponents& date)
91
{
107
{
92
    setValueAsInteger(date.month());
108
    setValueAsInteger(date.month());
Lines 95-101 void DateTimeSymbolicMonthFieldElement::setValueAsDate(const DateComponents& dat a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec7
95
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeYearFieldElement);
111
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeYearFieldElement);
96
112
97
DateTimeYearFieldElement::DateTimeYearFieldElement(Document& document, FieldOwner& fieldOwner)
113
DateTimeYearFieldElement::DateTimeYearFieldElement(Document& document, FieldOwner& fieldOwner)
98
    : DateTimeNumericFieldElement(document, fieldOwner, "----"_s)
114
    : DateTimeNumericFieldElement(document, fieldOwner, Range(DateComponents::minimumYear(), DateComponents::maximumYear()), "----"_s)
99
{
115
{
100
    static MainThreadNeverDestroyed<const AtomString> yearPseudoId("-webkit-datetime-edit-year-field", AtomString::ConstructFromLiteral);
116
    static MainThreadNeverDestroyed<const AtomString> yearPseudoId("-webkit-datetime-edit-year-field", AtomString::ConstructFromLiteral);
101
    initialize(yearPseudoId);
117
    initialize(yearPseudoId);
Lines 106-111 Ref<DateTimeYearFieldElement> DateTimeYearFieldElement::create(Document& documen a/Source/WebCore/html/shadow/DateTimeFieldElements.cpp_sec8
106
    return adoptRef(*new DateTimeYearFieldElement(document, fieldOwner));
122
    return adoptRef(*new DateTimeYearFieldElement(document, fieldOwner));
107
}
123
}
108
124
125
void DateTimeYearFieldElement::populateDateTimeFieldsState(DateTimeFieldsState& state)
126
{
127
    state.setYear(hasValue() ? valueAsInteger() : DateTimeFieldsState::emptyValue);
128
}
129
109
void DateTimeYearFieldElement::setValueAsDate(const DateComponents& date)
130
void DateTimeYearFieldElement::setValueAsDate(const DateComponents& date)
110
{
131
{
111
    setValueAsInteger(date.fullYear());
132
    setValueAsInteger(date.fullYear());
- a/Source/WebCore/html/shadow/DateTimeFieldElements.h +4 lines
Lines 44-49 private: a/Source/WebCore/html/shadow/DateTimeFieldElements.h_sec1
44
44
45
    // DateTimeFieldElement functions:
45
    // DateTimeFieldElement functions:
46
    void setValueAsDate(const DateComponents&);
46
    void setValueAsDate(const DateComponents&);
47
    void populateDateTimeFieldsState(DateTimeFieldsState&);
47
};
48
};
48
49
49
class DateTimeMonthFieldElement final : public DateTimeNumericFieldElement {
50
class DateTimeMonthFieldElement final : public DateTimeNumericFieldElement {
Lines 57-62 private: a/Source/WebCore/html/shadow/DateTimeFieldElements.h_sec2
57
58
58
    // DateTimeFieldElement functions:
59
    // DateTimeFieldElement functions:
59
    void setValueAsDate(const DateComponents&);
60
    void setValueAsDate(const DateComponents&);
61
    void populateDateTimeFieldsState(DateTimeFieldsState&);
60
};
62
};
61
63
62
class DateTimeSymbolicMonthFieldElement final : public DateTimeSymbolicFieldElement {
64
class DateTimeSymbolicMonthFieldElement final : public DateTimeSymbolicFieldElement {
Lines 70-75 private: a/Source/WebCore/html/shadow/DateTimeFieldElements.h_sec3
70
72
71
    // DateTimeFieldElement functions:
73
    // DateTimeFieldElement functions:
72
    void setValueAsDate(const DateComponents&);
74
    void setValueAsDate(const DateComponents&);
75
    void populateDateTimeFieldsState(DateTimeFieldsState&);
73
};
76
};
74
77
75
class DateTimeYearFieldElement final : public DateTimeNumericFieldElement {
78
class DateTimeYearFieldElement final : public DateTimeNumericFieldElement {
Lines 83-88 private: a/Source/WebCore/html/shadow/DateTimeFieldElements.h_sec4
83
86
84
    // DateTimeFieldElement functions:
87
    // DateTimeFieldElement functions:
85
    void setValueAsDate(const DateComponents&);
88
    void setValueAsDate(const DateComponents&);
89
    void populateDateTimeFieldsState(DateTimeFieldsState&);
86
};
90
};
87
91
88
} // namespace WebCore
92
} // namespace WebCore
- a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp -6 / +60 lines
Lines 29-43 a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp_sec1
29
29
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
30
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
31
31
32
#include "EventNames.h"
33
#include "KeyboardEvent.h"
32
#include "PlatformLocale.h"
34
#include "PlatformLocale.h"
33
#include <wtf/IsoMallocInlines.h>
35
#include <wtf/IsoMallocInlines.h>
34
36
35
namespace WebCore {
37
namespace WebCore {
36
38
39
constexpr Seconds typeAheadTimeout { 1_s };
40
41
int DateTimeNumericFieldElement::Range::clampValue(int value) const
42
{
43
    return std::min(std::max(value, minimum), maximum);
44
}
45
46
bool DateTimeNumericFieldElement::Range::isInRange(int value) const
47
{
48
    return value >= minimum && value <= maximum;
49
}
50
37
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeNumericFieldElement);
51
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeNumericFieldElement);
38
52
39
DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document& document, FieldOwner& fieldOwner, const String& placeholder)
53
DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const String& placeholder)
40
    : DateTimeFieldElement(document, fieldOwner)
54
    : DateTimeFieldElement(document, fieldOwner)
55
    , m_range(range)
41
    , m_placeholder(placeholder)
56
    , m_placeholder(placeholder)
42
{
57
{
43
}
58
}
Lines 45-50 DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document& document, Fie a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp_sec2
45
String DateTimeNumericFieldElement::formatValue(int value) const
60
String DateTimeNumericFieldElement::formatValue(int value) const
46
{
61
{
47
    Locale& locale = localeForOwner();
62
    Locale& locale = localeForOwner();
63
64
    if (m_range.maximum > 999)
65
        return locale.convertToLocalizedNumber(makeString(pad('0', 4, value)));
66
    if (m_range.maximum > 99)
67
        return locale.convertToLocalizedNumber(makeString(pad('0', 3, value)));
48
    return locale.convertToLocalizedNumber(makeString(pad('0', 2, value)));
68
    return locale.convertToLocalizedNumber(makeString(pad('0', 2, value)));
49
}
69
}
50
70
Lines 58-75 void DateTimeNumericFieldElement::initialize(const AtomString& pseudo) a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp_sec3
58
    DateTimeFieldElement::initialize(pseudo);
78
    DateTimeFieldElement::initialize(pseudo);
59
}
79
}
60
80
61
void DateTimeNumericFieldElement::setEmptyValue()
81
void DateTimeNumericFieldElement::setEmptyValue(EventBehavior eventBehavior)
62
{
82
{
63
    m_value = 0;
83
    m_value = 0;
64
    m_hasValue = false;
84
    m_hasValue = false;
65
    updateVisibleValue();
85
    m_typeAheadBuffer.clear();
86
    updateVisibleValue(eventBehavior);
66
}
87
}
67
88
68
void DateTimeNumericFieldElement::setValueAsInteger(int value)
89
void DateTimeNumericFieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
69
{
90
{
70
    m_value = value;
91
    m_value = m_range.clampValue(value);
71
    m_hasValue = true;
92
    m_hasValue = true;
72
    updateVisibleValue();
93
    updateVisibleValue(eventBehavior);
73
}
94
}
74
95
75
String DateTimeNumericFieldElement::value() const
96
String DateTimeNumericFieldElement::value() const
Lines 87-92 String DateTimeNumericFieldElement::visibleValue() const a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp_sec4
87
    return m_hasValue ? value() : m_placeholder;
108
    return m_hasValue ? value() : m_placeholder;
88
}
109
}
89
110
111
void DateTimeNumericFieldElement::handleKeyboardEvent(KeyboardEvent& keyboardEvent)
112
{
113
    if (keyboardEvent.type() != eventNames().keypressEvent)
114
        return;
115
116
    auto charCode = static_cast<UChar>(keyboardEvent.charCode());
117
    String number = localeForOwner().convertFromLocalizedNumber(String(&charCode, 1));
118
    int digit = number[0] - '0';
119
    if (digit < 0 || digit > 9)
120
        return;
121
122
    Seconds timeSinceLastDigitChar = keyboardEvent.timeStamp() - m_lastDigitCharTime;
123
    m_lastDigitCharTime = keyboardEvent.timeStamp();
124
125
    if (timeSinceLastDigitChar > typeAheadTimeout) {
126
        m_typeAheadBuffer.clear();
127
    } else if (auto length = m_typeAheadBuffer.length()) {
128
        unsigned maxLength = formatValue(m_range.maximum).length();
129
        if (length == maxLength)
130
            m_typeAheadBuffer.clear();
131
    }
132
133
    m_typeAheadBuffer.append(number);
134
    setValueAsInteger(m_typeAheadBuffer.toString().toInt(), DispatchInputAndChangeEvent);
135
136
    keyboardEvent.setDefaultHandled();
137
}
138
139
void DateTimeNumericFieldElement::didBlur()
140
{
141
    m_typeAheadBuffer.clear();
142
}
143
90
} // namespace WebCore
144
} // namespace WebCore
91
145
92
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
146
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
- a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h -3 / +19 lines
Lines 29-61 a/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h_sec1
29
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
29
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
30
30
31
#include "DateTimeFieldElement.h"
31
#include "DateTimeFieldElement.h"
32
#include <wtf/MonotonicTime.h>
33
#include <wtf/text/StringBuilder.h>
32
34
33
namespace WebCore {
35
namespace WebCore {
34
36
35
class DateTimeNumericFieldElement : public DateTimeFieldElement {
37
class DateTimeNumericFieldElement : public DateTimeFieldElement {
36
    WTF_MAKE_ISO_ALLOCATED(DateTimeNumericFieldElement);
38
    WTF_MAKE_ISO_ALLOCATED(DateTimeNumericFieldElement);
37
public:
39
public:
40
    struct Range {
41
        Range(int minimum, int maximum)
42
            : minimum(minimum), maximum(maximum) { }
43
        int clampValue(int) const;
44
        bool isInRange(int) const;
45
46
        int minimum;
47
        int maximum;
48
    };
38
49
39
protected:
50
protected:
40
    DateTimeNumericFieldElement(Document&, FieldOwner&, const String& placeholder);
51
    DateTimeNumericFieldElement(Document&, FieldOwner&, const Range&, const String& placeholder);
41
52
42
    // DateTimeFieldElement functions:
53
    // DateTimeFieldElement functions:
43
    bool hasValue() const final;
54
    bool hasValue() const final;
44
    void initialize(const AtomString&);
55
    void initialize(const AtomString&);
45
    void setEmptyValue() final;
56
    void setEmptyValue(EventBehavior = DispatchNoEvent) final;
46
    void setValueAsInteger(int) final;
57
    void setValueAsInteger(int, EventBehavior = DispatchNoEvent) final;
47
    int valueAsInteger() const final;
58
    int valueAsInteger() const final;
48
    String visibleValue() const final;
59
    String visibleValue() const final;
49
60
50
private:
61
private:
51
    // DateTimeFieldElement functions:
62
    // DateTimeFieldElement functions:
52
    String value() const final;
63
    String value() const final;
64
    void handleKeyboardEvent(KeyboardEvent&) final;
65
    void didBlur() final;
53
66
54
    String formatValue(int) const;
67
    String formatValue(int) const;
55
68
69
    const Range m_range;
56
    const String m_placeholder;
70
    const String m_placeholder;
57
    int m_value { 0 };
71
    int m_value { 0 };
58
    bool m_hasValue { false };
72
    bool m_hasValue { false };
73
    StringBuilder m_typeAheadBuffer;
74
    MonotonicTime m_lastDigitCharTime;
59
};
75
};
60
76
61
} // namespace WebCore
77
} // namespace WebCore
- a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp -4 / +9 lines
Lines 63-78 void DateTimeSymbolicFieldElement::initialize(const AtomString& pseudo) a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp_sec1
63
    DateTimeFieldElement::initialize(pseudo);
63
    DateTimeFieldElement::initialize(pseudo);
64
}
64
}
65
65
66
void DateTimeSymbolicFieldElement::setEmptyValue()
66
void DateTimeSymbolicFieldElement::setEmptyValue(EventBehavior eventBehavior)
67
{
67
{
68
    m_selectedIndex = invalidIndex;
68
    m_selectedIndex = invalidIndex;
69
    updateVisibleValue();
69
    updateVisibleValue(eventBehavior);
70
}
70
}
71
71
72
void DateTimeSymbolicFieldElement::setValueAsInteger(int newSelectedIndex)
72
void DateTimeSymbolicFieldElement::setValueAsInteger(int newSelectedIndex, EventBehavior eventBehavior)
73
{
73
{
74
    m_selectedIndex = std::max(0, std::min(newSelectedIndex, static_cast<int>(m_symbols.size() - 1)));
74
    m_selectedIndex = std::max(0, std::min(newSelectedIndex, static_cast<int>(m_symbols.size() - 1)));
75
    updateVisibleValue();
75
    updateVisibleValue(eventBehavior);
76
}
76
}
77
77
78
String DateTimeSymbolicFieldElement::value() const
78
String DateTimeSymbolicFieldElement::value() const
Lines 95-100 String DateTimeSymbolicFieldElement::visibleValue() const a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp_sec2
95
    return hasValue() ? m_symbols[m_selectedIndex] : visibleEmptyValue();
95
    return hasValue() ? m_symbols[m_selectedIndex] : visibleEmptyValue();
96
}
96
}
97
97
98
void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent&)
99
{
100
    // FIXME: Implement after adding layout for <input type=time>.
101
}
102
98
} // namespace WebCore
103
} // namespace WebCore
99
104
100
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
105
#endif // ENABLE(DATE_AND_TIME_INPUT_TYPES)
- a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h -2 / +3 lines
Lines 39-46 protected: a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h_sec1
39
    size_t symbolsSize() const { return m_symbols.size(); }
39
    size_t symbolsSize() const { return m_symbols.size(); }
40
    bool hasValue() const final;
40
    bool hasValue() const final;
41
    void initialize(const AtomString& pseudo);
41
    void initialize(const AtomString& pseudo);
42
    void setEmptyValue() final;
42
    void setEmptyValue(EventBehavior = DispatchNoEvent) final;
43
    void setValueAsInteger(int) final;
43
    void setValueAsInteger(int, EventBehavior = DispatchNoEvent) final;
44
    int valueAsInteger() const final;
44
    int valueAsInteger() const final;
45
45
46
private:
46
private:
Lines 51-56 private: a/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h_sec2
51
    // DateTimeFieldElement functions:
51
    // DateTimeFieldElement functions:
52
    String value() const final;
52
    String value() const final;
53
    String visibleValue() const final;
53
    String visibleValue() const final;
54
    void handleKeyboardEvent(KeyboardEvent&) final;
54
55
55
    const Vector<String> m_symbols;
56
    const Vector<String> m_symbols;
56
57
- a/Source/WebCore/platform/DateComponents.cpp -21 / +13 lines
Lines 41-55 a/Source/WebCore/platform/DateComponents.cpp_sec1
41
41
42
namespace WebCore {
42
namespace WebCore {
43
43
44
// HTML uses ISO-8601 format with year >= 1. Gregorian calendar started in
44
// HTML defines minimum week of year is one.
45
// 1582. However, we need to support 0001-01-01 in Gregorian calendar rule.
46
static constexpr int minimumYear = 1;
47
48
// Date in ECMAScript can't represent dates later than 275760-09-13T00:00Z.
49
// So, we have the same upper limit in HTML5 date/time types.
50
static constexpr int maximumYear = 275760;
51
52
// HTMLdefines minimum week of year is one.
53
static constexpr int minimumWeekNumber = 1;
45
static constexpr int minimumWeekNumber = 1;
54
46
55
// HTML defines maximum week of year is 53.
47
// HTML defines maximum week of year is 53.
Lines 151-157 template<typename CharacterType> bool DateComponents::parseYear(StringParsingBuf a/Source/WebCore/platform/DateComponents.cpp_sec2
151
    if (digitsLength < 4)
143
    if (digitsLength < 4)
152
        return false;
144
        return false;
153
145
154
    auto year = parseIntWithinLimits(buffer, digitsLength, minimumYear, maximumYear);
146
    auto year = parseIntWithinLimits(buffer, digitsLength, minimumYear(), maximumYear());
155
    if (!year)
147
    if (!year)
156
        return false;
148
        return false;
157
149
Lines 161-178 template<typename CharacterType> bool DateComponents::parseYear(StringParsingBuf a/Source/WebCore/platform/DateComponents.cpp_sec3
161
153
162
static bool withinHTMLDateLimits(int year, int month)
154
static bool withinHTMLDateLimits(int year, int month)
163
{
155
{
164
    if (year < minimumYear)
156
    if (year < DateComponents::minimumYear())
165
        return false;
157
        return false;
166
    if (year < maximumYear)
158
    if (year < DateComponents::maximumYear())
167
        return true;
159
        return true;
168
    return month <= maximumMonthInMaximumYear;
160
    return month <= maximumMonthInMaximumYear;
169
}
161
}
170
162
171
static bool withinHTMLDateLimits(int year, int month, int monthDay)
163
static bool withinHTMLDateLimits(int year, int month, int monthDay)
172
{
164
{
173
    if (year < minimumYear)
165
    if (year < DateComponents::minimumYear())
174
        return false;
166
        return false;
175
    if (year < maximumYear)
167
    if (year < DateComponents::maximumYear())
176
        return true;
168
        return true;
177
    if (month < maximumMonthInMaximumYear)
169
    if (month < maximumMonthInMaximumYear)
178
        return true;
170
        return true;
Lines 181-189 static bool withinHTMLDateLimits(int year, int month, int monthDay) a/Source/WebCore/platform/DateComponents.cpp_sec4
181
173
182
static bool withinHTMLDateLimits(int year, int month, int monthDay, int hour, int minute, int second, int millisecond)
174
static bool withinHTMLDateLimits(int year, int month, int monthDay, int hour, int minute, int second, int millisecond)
183
{
175
{
184
    if (year < minimumYear)
176
    if (year < DateComponents::minimumYear())
185
        return false;
177
        return false;
186
    if (year < maximumYear)
178
    if (year < DateComponents::maximumYear())
187
        return true;
179
        return true;
188
    if (month < maximumMonthInMaximumYear)
180
    if (month < maximumMonthInMaximumYear)
189
        return true;
181
        return true;
Lines 436-442 template<typename CharacterType> bool DateComponents::parseWeek(StringParsingBuf a/Source/WebCore/platform/DateComponents.cpp_sec5
436
    if (!week)
428
    if (!week)
437
        return false;
429
        return false;
438
430
439
    if (m_year == maximumYear && *week > maximumWeekInMaximumYear)
431
    if (m_year == maximumYear() && *week > maximumWeekInMaximumYear)
440
        return false;
432
        return false;
441
433
442
    m_week = *week;
434
    m_week = *week;
Lines 656-662 bool DateComponents::setMonthsSinceEpoch(double months) a/Source/WebCore/platform/DateComponents.cpp_sec6
656
    months = round(months);
648
    months = round(months);
657
    double doubleMonth = positiveFmod(months, 12);
649
    double doubleMonth = positiveFmod(months, 12);
658
    double doubleYear = 1970 + (months - doubleMonth) / 12;
650
    double doubleYear = 1970 + (months - doubleMonth) / 12;
659
    if (doubleYear < minimumYear || maximumYear < doubleYear)
651
    if (doubleYear < minimumYear() || maximumYear() < doubleYear)
660
        return false;
652
        return false;
661
    int year = static_cast<int>(doubleYear);
653
    int year = static_cast<int>(doubleYear);
662
    int month = static_cast<int>(doubleMonth);
654
    int month = static_cast<int>(doubleMonth);
Lines 686-692 bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) a/Source/WebCore/platform/DateComponents.cpp_sec7
686
    ms = round(ms);
678
    ms = round(ms);
687
679
688
    m_year = msToYear(ms);
680
    m_year = msToYear(ms);
689
    if (m_year < minimumYear || m_year > maximumYear)
681
    if (m_year < minimumYear() || m_year > maximumYear())
690
        return false;
682
        return false;
691
683
692
    int yearDay = dayInYear(ms, m_year);
684
    int yearDay = dayInYear(ms, m_year);
Lines 694-700 bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) a/Source/WebCore/platform/DateComponents.cpp_sec8
694
    if (yearDay < offset) {
686
    if (yearDay < offset) {
695
        // The day belongs to the last week of the previous year.
687
        // The day belongs to the last week of the previous year.
696
        m_year--;
688
        m_year--;
697
        if (m_year <= minimumYear)
689
        if (m_year <= minimumYear())
698
            return false;
690
            return false;
699
        m_week = maxWeekNumberInYear();
691
        m_week = maxWeekNumberInYear();
700
    } else {
692
    } else {
Lines 703-709 bool DateComponents::setMillisecondsSinceEpochForWeek(double ms) a/Source/WebCore/platform/DateComponents.cpp_sec9
703
            m_year++;
695
            m_year++;
704
            m_week = 1;
696
            m_week = 1;
705
        }
697
        }
706
        if (m_year > maximumYear || (m_year == maximumYear && m_week > maximumWeekInMaximumYear))
698
        if (m_year > maximumYear() || (m_year == maximumYear() && m_week > maximumWeekInMaximumYear))
707
            return false;
699
            return false;
708
    }
700
    }
709
    m_type = DateComponentsType::Week;
701
    m_type = DateComponentsType::Week;
- a/Source/WebCore/platform/DateComponents.h +8 lines
Lines 137-142 public: a/Source/WebCore/platform/DateComponents.h_sec1
137
    static constexpr inline double maximumTime() { return 86399999; } // 23:59:59.999
137
    static constexpr inline double maximumTime() { return 86399999; } // 23:59:59.999
138
    static constexpr inline double maximumWeek() { return 8639999568000000.0; } // 275760-09-08, the Monday of the week including 275760-09-13.
138
    static constexpr inline double maximumWeek() { return 8639999568000000.0; } // 275760-09-08, the Monday of the week including 275760-09-13.
139
139
140
    // HTML uses ISO-8601 format with year >= 1. Gregorian calendar started in
141
    // 1582. However, we need to support 0001-01-01 in Gregorian calendar rule.
142
    static constexpr inline int minimumYear() { return 1; }
143
144
    // Date in ECMAScript can't represent dates later than 275760-09-13T00:00Z.
145
    // So, we have the same upper limit in HTML5 date/time types.
146
    static constexpr inline int maximumYear() { return 275760; }
147
140
private:
148
private:
141
    template<typename CharacterType> bool parseYear(StringParsingBuffer<CharacterType>&);
149
    template<typename CharacterType> bool parseYear(StringParsingBuffer<CharacterType>&);
142
    template<typename CharacterType> bool parseTimeZone(StringParsingBuffer<CharacterType>&);
150
    template<typename CharacterType> bool parseTimeZone(StringParsingBuffer<CharacterType>&);
- a/LayoutTests/ChangeLog +21 lines
Lines 1-3 a/LayoutTests/ChangeLog_sec1
1
2020-08-28  Aditya Keerthi  <akeerthi@apple.com>
2
3
        [macOS] Handle events for date inputs with editable components
4
        https://bugs.webkit.org/show_bug.cgi?id=215938
5
6
        Reviewed by NOBODY (OOPS!).
7
8
        Added tests to verify correctness for keyboard and mouse inputs in date
9
        inputs with editable components. These tests also ensure that the
10
        appropriate events are dispatched: "click", "blur", "focus", "input"
11
        and "change".
12
13
        * TestExpectations:
14
        * fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events-expected.txt: Added.
15
        * fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events.html: Added.
16
        * fast/forms/date/date-editable-components/date-editable-components-keyboard-events-expected.txt: Added.
17
        * fast/forms/date/date-editable-components/date-editable-components-keyboard-events.html: Added.
18
        * fast/forms/date/date-editable-components/date-editable-components-mouse-events-expected.txt: Added.
19
        * fast/forms/date/date-editable-components/date-editable-components-mouse-events.html: Added.
20
        * platform/mac-wk2/TestExpectations:
21
1
2020-08-31  Aditya Keerthi  <akeerthi@apple.com>
22
2020-08-31  Aditya Keerthi  <akeerthi@apple.com>
2
23
3
        [macOS] Date inputs should contain editable components
24
        [macOS] Date inputs should contain editable components
- a/LayoutTests/TestExpectations +1 lines
Lines 30-35 editing/undo-manager [ Skip ] a/LayoutTests/TestExpectations_sec1
30
tiled-drawing [ Skip ]
30
tiled-drawing [ Skip ]
31
fast/css/ios [ Skip ]
31
fast/css/ios [ Skip ]
32
fast/css/watchos [ Skip ]
32
fast/css/watchos [ Skip ]
33
fast/forms/date/date-editable-components [ Skip ]
33
fast/dom/Window/watchos [ Skip ]
34
fast/dom/Window/watchos [ Skip ]
34
fast/forms/select/mac-wk2 [ Skip ]
35
fast/forms/select/mac-wk2 [ Skip ]
35
fast/forms/textarea/ios [ Skip ]
36
fast/forms/textarea/ios [ Skip ]
- a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events-expected.txt +40 lines
Line 0 a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events-expected.txt_sec1
1
Test for focus and blur events for <input type=date>
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
Focus/blur using mouse
7
8
PASS focusEventsFired is 1
9
PASS blurEventsFired is 0
10
PASS focusEventsFired is 1
11
PASS blurEventsFired is 0
12
PASS focusEventsFired is 1
13
PASS blurEventsFired is 0
14
PASS focusEventsFired is 1
15
PASS blurEventsFired is 0
16
PASS focusEventsFired is 1
17
PASS blurEventsFired is 1
18
19
Focus/blur using keyboard
20
21
PASS focusEventsFired is 1
22
PASS blurEventsFired is 0
23
PASS focusEventsFired is 1
24
PASS blurEventsFired is 0
25
PASS focusEventsFired is 1
26
PASS blurEventsFired is 0
27
PASS focusEventsFired is 1
28
PASS blurEventsFired is 1
29
PASS focusEventsFired is 2
30
PASS blurEventsFired is 1
31
PASS focusEventsFired is 2
32
PASS blurEventsFired is 1
33
PASS focusEventsFired is 2
34
PASS blurEventsFired is 1
35
PASS focusEventsFired is 2
36
PASS blurEventsFired is 2
37
PASS successfullyParsed is true
38
39
TEST COMPLETE
40
  
- a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events.html +122 lines
Line 0 a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-focus-and-blur-events.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<script src="../../../../resources/js-test-pre.js"></script>
5
<script src="../../../../resources/ui-helper.js"></script>
6
<style>
7
input {
8
    width: 300px;
9
}
10
11
input::-webkit-datetime-edit-text {
12
    font-size: 30px;
13
}
14
15
input::-webkit-datetime-edit-month-field {
16
    font-size: 30px;
17
}
18
19
input::-webkit-datetime-edit-day-field {
20
    font-size: 30px;
21
}
22
23
input::-webkit-datetime-edit-year-field {
24
    font-size: 30px;
25
}
26
</style>
27
</head>
28
<body>
29
30
<input id="before" type="text">
31
<input id="input" type="date" value="2020-08-26">
32
<input id="after" type="text">
33
34
<script>
35
36
description("Test for focus and blur events for &lt;input type=date&gt;");
37
38
blurEventsFired = 0;
39
function onBlurEvent() {
40
    blurEventsFired++;
41
}
42
43
focusEventsFired = 0;
44
function onFocusEvent() {
45
    focusEventsFired++;
46
}
47
48
function assertFocusAndBlurCount(numFocusEvents, numBlurEvents) {
49
    shouldBe("focusEventsFired", numFocusEvents.toString());
50
    shouldBe("blurEventsFired", numBlurEvents.toString());
51
}
52
53
function resetFocusAndBlurCount() {
54
    blurEventsFired = 0;
55
    focusEventsFired = 0;
56
}
57
58
function mouseClickOn(x, y) {
59
    if (!window.eventSender)
60
        return;
61
    eventSender.mouseMoveTo(x + input.offsetLeft, y + input.offsetTop);
62
    eventSender.mouseDown();
63
    eventSender.mouseUp();
64
}
65
66
input.addEventListener("blur", onBlurEvent);
67
input.addEventListener("focus", onFocusEvent);
68
69
const center = input.offsetHeight / 2;
70
71
debug("Focus/blur using mouse\n");
72
73
// Click on month field.
74
mouseClickOn(20, center);
75
assertFocusAndBlurCount(1, 0);
76
// Click on day field.
77
mouseClickOn(60, center);
78
assertFocusAndBlurCount(1, 0);
79
// Click on year field.
80
mouseClickOn(120, center);
81
assertFocusAndBlurCount(1, 0);
82
// Click on control, but not a specific field.
83
mouseClickOn(250, center);
84
assertFocusAndBlurCount(1, 0);
85
// Click outside control.
86
mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
87
assertFocusAndBlurCount(1, 1);
88
resetFocusAndBlurCount();
89
90
debug("\nFocus/blur using keyboard\n");
91
92
UIHelper.activateElement(before);
93
// Focus on month field.
94
UIHelper.keyDown("\t");
95
assertFocusAndBlurCount(1, 0);
96
// Focus on day field.
97
UIHelper.keyDown("\t");
98
assertFocusAndBlurCount(1, 0);
99
// Focus on year field.
100
UIHelper.keyDown("\t");
101
assertFocusAndBlurCount(1, 0);
102
// Focus out.
103
UIHelper.keyDown("\t");
104
assertFocusAndBlurCount(1, 1);
105
// Focus on year field.
106
UIHelper.keyDown("\t", ["shiftKey"]);
107
assertFocusAndBlurCount(2, 1);
108
// Focus on day field.
109
UIHelper.keyDown("\t", ["shiftKey"]);
110
assertFocusAndBlurCount(2, 1);
111
// Focus on month field.
112
UIHelper.keyDown("\t", ["shiftKey"]);
113
assertFocusAndBlurCount(2, 1);
114
// Focus out.
115
UIHelper.keyDown("\t", ["shiftKey"]);
116
assertFocusAndBlurCount(2, 2);
117
118
</script>
119
120
<script src="../../../../resources/js-test-post.js"></script>
121
</body>
122
</html>
- a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-keyboard-events-expected.txt +59 lines
Line 0 a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-keyboard-events-expected.txt_sec1
1
Test for keyboard operations for <input type=date>
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
7
Digit keys
8
PASS input.value is "2012-09-02"
9
PASS changeEventsFired is 4
10
PASS inputEventsFired is 4
11
12
Digit keys with leading zero
13
PASS input.value is "0034-05-06"
14
PASS changeEventsFired is 3
15
PASS inputEventsFired is 3
16
17
Digit keys and backspace key
18
PASS input.value is "2020-02-04"
19
PASS changeEventsFired is 6
20
PASS inputEventsFired is 6
21
22
Digit keys with timeout
23
PASS input.value is "0001-02-04"
24
PASS changeEventsFired is 2
25
PASS inputEventsFired is 2
26
27
Digit keys clamp value
28
PASS input.value is "9999-12-31"
29
PASS changeEventsFired is 4
30
PASS inputEventsFired is 4
31
32
Left/Right arrow keys
33
PASS input.value is "0002-02-02"
34
PASS input.value is "0002-03-03"
35
PASS changeEventsFired is 3
36
PASS inputEventsFired is 3
37
38
Tab key
39
PASS input.value is "0002-02-02"
40
PASS document.activeElement.id is "after"
41
PASS input.value is "0002-03-03"
42
PASS document.activeElement.id is "before"
43
PASS changeEventsFired is 3
44
PASS inputEventsFired is 3
45
46
Backspace key
47
PASS input.value is ""
48
PASS input.value is "2020-07-26"
49
PASS changeEventsFired is 2
50
PASS inputEventsFired is 2
51
52
Delete key
53
PASS input.value is ""
54
PASS changeEventsFired is 1
55
PASS inputEventsFired is 1
56
PASS successfullyParsed is true
57
58
TEST COMPLETE
59
  
- a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-keyboard-events.html +174 lines
Line 0 a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-keyboard-events.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<script src="../../../../resources/js-test-pre.js"></script>
5
<script src="../../../../resources/ui-helper.js"></script>
6
</head>
7
<body>
8
9
<input id="before" type="text">
10
<input id="input" type="date">
11
<input id="after" type="text">
12
13
<script>
14
15
jsTestIsAsync = true;
16
17
changeEventsFired = 0;
18
function onChangeEvent() {
19
    changeEventsFired++;
20
}
21
22
inputEventsFired = 0;
23
function onInputEvent() {
24
    inputEventsFired++;
25
}
26
27
function beginTest(title, value) {
28
    debug("\n" + title);
29
    input.value = value || "";
30
    input.blur();
31
    input.focus();
32
33
    changeEventsFired = 0;
34
    inputEventsFired = 0;
35
}
36
37
input.addEventListener("change", onChangeEvent);
38
input.addEventListener("input", onInputEvent);
39
40
addEventListener("load", async () => {
41
    description("Test for keyboard operations for &lt;input type=date&gt;");
42
43
    beginTest("Digit keys");                               // [mm]/dd/yyyy
44
    UIHelper.keyDown("9");                                 // -> [09]/dd/yyyy
45
    UIHelper.keyDown("rightArrow");                        // -> 09/[dd]/yyyy
46
    UIHelper.keyDown("2");                                 // -> 09/[02]/yyyy
47
    UIHelper.keyDown("rightArrow");                        // -> 09/02/[yyyy]
48
    UIHelper.keyDown("2");                                 // -> 09/02/[0002]
49
    UIHelper.keyDown("0");                                 // -> 09/02/[0020]
50
    UIHelper.keyDown("1");                                 // -> 09/02/[0201]
51
    UIHelper.keyDown("2");                                 // -> 09/02/[2012]
52
    UIHelper.keyDown("A");                                 // Ignored.
53
    shouldBeEqualToString("input.value", "2012-09-02");
54
    shouldBe("changeEventsFired", "4");
55
    shouldBe("inputEventsFired", "4");
56
57
    beginTest("Digit keys with leading zero");             // [mm]/dd/yyyy
58
    UIHelper.keyDown("0");                                 // -> [00]/dd/yyyy
59
    UIHelper.keyDown("5");                                 // -> [05]/dd/yyyy
60
    UIHelper.keyDown("rightArrow");                        // -> 05/[dd]/yyyy
61
    UIHelper.keyDown("0");                                 // -> 05/[00]/yyyy
62
    UIHelper.keyDown("6");                                 // -> 05/[06]/yyyy
63
    UIHelper.keyDown("rightArrow");                        // -> 05/06/[yyyy]
64
    UIHelper.keyDown("0");                                 // -> 05/06/[0001]
65
    UIHelper.keyDown("0");                                 // -> 05/06/[0001]
66
    UIHelper.keyDown("3");                                 // -> 05/06/[0003]
67
    UIHelper.keyDown("4");                                 // -> 05/06/[0034]
68
    shouldBeEqualToString("input.value", "0034-05-06");
69
    shouldBe("changeEventsFired", "3");
70
    shouldBe("inputEventsFired", "3");
71
72
    beginTest("Digit keys and backspace key");             // [mm]/dd/yyyy
73
    UIHelper.keyDown("1");                                 // -> [01]/dd/yyyy
74
    UIHelper.keyDown("\b");                                // -> [mm]/dd/yyyy
75
    UIHelper.keyDown("2");                                 // -> [02]/dd/yyyy
76
    UIHelper.keyDown("rightArrow");                        // -> 02/[dd]/yyyy
77
    UIHelper.keyDown("3");                                 // -> 02/[03]/yyyy
78
    UIHelper.keyDown("\b");                                // -> 02/[dd]/yyyy
79
    UIHelper.keyDown("4");                                 // -> 02/[04]/yyyy
80
    UIHelper.keyDown("rightArrow");                        // -> 02/04/[yyyy]
81
    UIHelper.keyDown("4");                                 // -> 02/04/[0004]
82
    UIHelper.keyDown("\b");                                // -> 02/04/[yyyy]
83
    UIHelper.keyDown("2");                                 // -> 02/04/[0002]
84
    UIHelper.keyDown("0");                                 // -> 02/04/[0020]
85
    UIHelper.keyDown("2");                                 // -> 02/04/[0202]
86
    UIHelper.keyDown("0");                                 // -> 02/04/[2020]
87
    shouldBeEqualToString("input.value", "2020-02-04");
88
    shouldBe("changeEventsFired", "6");
89
    shouldBe("inputEventsFired", "6");
90
91
    beginTest("Digit keys with timeout");                  // [mm]/dd/yyyy
92
    UIHelper.keyDown("2");                                 // -> [02]/dd/yyyy
93
    UIHelper.keyDown("rightArrow");                        // -> 02/[dd]/yyyy
94
    UIHelper.keyDown("4");                                 // -> 02/[04]/yyyy
95
    UIHelper.keyDown("rightArrow");                        // -> 02/04/[yyyy]
96
    UIHelper.keyDown("4");                                 // -> 02/04/[0004]
97
    await UIHelper.delayFor(1500);                         // Wait.
98
    UIHelper.keyDown("1");                                 // -> 02/04/[0001]
99
    shouldBeEqualToString("input.value", "0001-02-04");
100
    shouldBe("changeEventsFired", "2");
101
    shouldBe("inputEventsFired", "2");
102
103
    beginTest("Digit keys clamp value");                   // [mm]/dd/yyyy
104
    UIHelper.keyDown("9");                                 // -> [09]/dd/yyyy
105
    UIHelper.keyDown("9");                                 // -> [12]/dd/yyyy
106
    UIHelper.keyDown("rightArrow");                        // -> 12/[dd]/yyyy
107
    UIHelper.keyDown("9");                                 // -> 12/[09]/yyyy
108
    UIHelper.keyDown("9");                                 // -> 12/[31]/yyyy
109
    UIHelper.keyDown("rightArrow");                        // -> 12/31/[yyyy]
110
    UIHelper.keyDown("9");                                 // -> 12/31/[0009]
111
    UIHelper.keyDown("9");                                 // -> 12/31/[0099]
112
    UIHelper.keyDown("9");                                 // -> 12/31/[0999]
113
    UIHelper.keyDown("9");                                 // -> 12/31/[9999]
114
    shouldBeEqualToString("input.value", "9999-12-31");
115
    shouldBe("changeEventsFired", "4");
116
    shouldBe("inputEventsFired", "4");
117
118
    beginTest("Left/Right arrow keys");                    // [mm]/dd/yyyy
119
    UIHelper.keyDown("2");                                 // -> [02]/dd/yyyy
120
    UIHelper.keyDown("rightArrow");                        // -> 02/[dd]/yyyy
121
    UIHelper.keyDown("2");                                 // -> 02/[02]/yyyy
122
    UIHelper.keyDown("rightArrow");                        // -> 02/02/[yyyy]
123
    UIHelper.keyDown("2");                                 // -> 02/02/[0002]
124
    shouldBeEqualToString("input.value", "0002-02-02");
125
    UIHelper.keyDown("leftArrow");                         // -> 02/[02]/0002
126
    UIHelper.keyDown("3");                                 // -> 02/[03]/0002
127
    UIHelper.keyDown("leftArrow");                         // -> [02]/03/0002
128
    UIHelper.keyDown("3");                                 // -> [03]/03/0002
129
    shouldBeEqualToString("input.value", "0002-03-03");
130
    shouldBe("changeEventsFired", "3");
131
    shouldBe("inputEventsFired", "3");
132
133
    beginTest("Tab key");
134
    UIHelper.keyDown("2");                                 // -> [02]/dd/yyyy
135
    UIHelper.keyDown("\t");                                // -> 02/[dd]/yyyy
136
    UIHelper.keyDown("2");                                 // -> 02/[02]/yyyy
137
    UIHelper.keyDown("\t");                                // -> 02/02/[yyyy]
138
    UIHelper.keyDown("2");                                 // -> 02/02/[0002]
139
    shouldBeEqualToString("input.value", "0002-02-02");
140
    UIHelper.keyDown("\t");                                // Focus out.
141
    shouldBeEqualToString("document.activeElement.id", "after");
142
    UIHelper.keyDown("\t", ["shiftKey"]);                  // -> 02/02/[0002]
143
    UIHelper.keyDown("\t", ["shiftKey"]);                  // -> 02/[02]/0002
144
    UIHelper.keyDown("3");                                 // -> 02/[03]/0002
145
    UIHelper.keyDown("\t", ["shiftKey"]);                  // -> [02]/03/0002
146
    UIHelper.keyDown("3");                                 // -> [03]/03/0002
147
    shouldBeEqualToString("input.value", "0002-03-03");
148
    UIHelper.keyDown("\t", ["shiftKey"]);                  // Focus out.
149
    shouldBeEqualToString("document.activeElement.id", "before");
150
    shouldBe("changeEventsFired", "3");
151
    shouldBe("inputEventsFired", "3");
152
153
    beginTest("Backspace key", "2020-08-26");              // [08]/26/2020
154
    UIHelper.keyDown("\b");                                // -> [mm]/26/2020
155
    shouldBeEqualToString("input.value", "");
156
    UIHelper.keyDown("7");                                 // -> [07]/26/2020
157
    shouldBeEqualToString("input.value", "2020-07-26");
158
    shouldBe("changeEventsFired", "2");
159
    shouldBe("inputEventsFired", "2");
160
161
    beginTest("Delete key", "2020-08-26");                 // [08]/26/2021
162
    UIHelper.keyDown("delete");                            // -> [mm]/26/2021
163
    shouldBeEqualToString("input.value", "");
164
    shouldBe("changeEventsFired", "1");
165
    shouldBe("inputEventsFired", "1");
166
167
    finishJSTest();
168
});
169
170
</script>
171
172
<script src="../../../../resources/js-test-post.js"></script>
173
</body>
174
</html>
- a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-mouse-events-expected.txt +15 lines
Line 0 a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-mouse-events-expected.txt_sec1
1
Test for mouse events for <input type=date>
2
3
On success, you will see a series of "PASS" messages, followed by "TEST COMPLETE".
4
5
6
PASS input.value is "2020-09-26"
7
PASS input.value is "2020-09-12"
8
PASS input.value is "3030-09-12"
9
PASS input.value is "3030-05-12"
10
PASS input.value is "3030-05-12"
11
PASS clickEventsFired is 4
12
PASS successfullyParsed is true
13
14
TEST COMPLETE
15
- a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-mouse-events.html +87 lines
Line 0 a/LayoutTests/fast/forms/date/date-editable-components/date-editable-components-mouse-events.html_sec1
1
<!DOCTYPE html>
2
<html>
3
<head>
4
<script src="../../../../resources/js-test-pre.js"></script>
5
<script src="../../../../resources/ui-helper.js"></script>
6
<style>
7
input {
8
    width: 300px;
9
}
10
11
input::-webkit-datetime-edit-text {
12
    font-size: 30px;
13
}
14
15
input::-webkit-datetime-edit-month-field {
16
    font-size: 30px;
17
}
18
19
input::-webkit-datetime-edit-day-field {
20
    font-size: 30px;
21
}
22
23
input::-webkit-datetime-edit-year-field {
24
    font-size: 30px;
25
}
26
</style>
27
</head>
28
<body>
29
30
<input id="input" type="date" value="2020-08-26">
31
32
<script>
33
34
description("Test for mouse events for &lt;input type=date&gt;");
35
36
clickEventsFired = 0;
37
function onClickEvent() {
38
    clickEventsFired++;
39
}
40
41
function mouseClickOn(x, y) {
42
    if (!window.eventSender)
43
        return;
44
    eventSender.mouseMoveTo(x + input.offsetLeft, y + input.offsetTop);
45
    eventSender.mouseDown();
46
    eventSender.mouseUp();
47
}
48
49
input.addEventListener("click", onClickEvent);
50
const center = input.offsetHeight / 2;
51
52
// Click on month field.
53
mouseClickOn(20, center);
54
UIHelper.keyDown("9");
55
shouldBeEqualToString("input.value", "2020-09-26");
56
57
// Click on day field.
58
mouseClickOn(60, center);
59
UIHelper.keyDown("1");
60
UIHelper.keyDown("2");
61
shouldBeEqualToString("input.value", "2020-09-12");
62
63
// Click on year field.
64
mouseClickOn(120, center);
65
UIHelper.keyDown("3");
66
UIHelper.keyDown("0");
67
UIHelper.keyDown("3");
68
UIHelper.keyDown("0");
69
shouldBeEqualToString("input.value", "3030-09-12");
70
71
// Click on control, but not a specific field, defaults to first field.
72
mouseClickOn(250, center);
73
UIHelper.keyDown("5");
74
shouldBeEqualToString("input.value", "3030-05-12");
75
76
// Click outside control.
77
mouseClickOn(input.offsetWidth + 5, input.offsetHeight + 5);
78
UIHelper.keyDown("5");
79
shouldBeEqualToString("input.value", "3030-05-12");
80
81
shouldBe("clickEventsFired", "4");
82
83
</script>
84
85
<script src="../../../../resources/js-test-post.js"></script>
86
</body>
87
</html>
- a/LayoutTests/platform/mac-wk2/TestExpectations +1 lines
Lines 12-17 editing/find [ Pass ] a/LayoutTests/platform/mac-wk2/TestExpectations_sec1
12
editing/undo-manager [ Pass ]
12
editing/undo-manager [ Pass ]
13
editing/pasteboard/dom-paste [ Pass ]
13
editing/pasteboard/dom-paste [ Pass ]
14
fast/events/cursors [ Pass ]
14
fast/events/cursors [ Pass ]
15
fast/forms/date/date-editable-components [ Pass ]
15
fast/forms/select/mac-wk2 [ Pass ]
16
fast/forms/select/mac-wk2 [ Pass ]
16
fast/sandbox/mac [ Pass ]
17
fast/sandbox/mac [ Pass ]
17
fast/scrolling/mac [ Pass ]
18
fast/scrolling/mac [ Pass ]

Return to Bug 215938