Diff
Modified: trunk/Source/WebCore/ChangeLog (270244 => 270245)
--- trunk/Source/WebCore/ChangeLog 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/ChangeLog 2020-11-30 16:35:19 UTC (rev 270245)
@@ -1,3 +1,86 @@
+2020-11-30 Aditya Keerthi <[email protected]>
+
+ Use real dates and times as placeholders for date/time inputs with editable components
+ https://bugs.webkit.org/show_bug.cgi?id=219216
+ <rdar://problem/71636615>
+
+ Reviewed by Devin Rousso.
+
+ Currently, date/time inputs with editable components have "--" as a
+ placeholder when the input is empty. This is undesirable for two reasons:
+
+ 1. "--" does not fill the width of the component, leading to an unpleasant appearance.
+ 2. The order of the date/time components is unclear.
+
+ To resolve these issues, this patch introduces real dates and times as
+ placeholders. For dates, the current date is used as a placeholder.
+ For times, a fixed time (such as "12:30 PM") is used, to avoid being
+ overly specific. Note that the second and millisecond fields for times
+ will always have "00" and "000" as a placeholder respectively.
+
+ When the placeholder is visible, the text color is changed to dark gray,
+ matching the placeholder in regular text inputs. Note that date/time
+ placeholders are not customizable in any way, as it is an unspecified aspect
+ of the element. Separators are left in the existing text color, to avoid
+ making the input look disabled.
+
+ * html/shadow/DateTimeEditElement.cpp:
+ (WebCore::DateTimeEditElement::DateTimeEditElement):
+ (WebCore::DateTimeEditElement::placeholderDate const):
+ * html/shadow/DateTimeEditElement.h:
+
+ Introduced m_placeholderDate, which is set to the current date.
+
+ * html/shadow/DateTimeFieldElement.cpp:
+ (WebCore::DateTimeFieldElement::setEmptyValue):
+ (WebCore::DateTimeFieldElement::setValueAsInteger):
+ (WebCore::DateTimeFieldElement::visibleValue const):
+ (WebCore::DateTimeFieldElement::updateVisibleValue):
+
+ Removed early return when the previous visible value is equal to the
+ updated visible value. This can occur when the placeholder value is equal
+ to the value entered by the user. In these instances, we should still
+ dispatch input and change events.
+
+ * html/shadow/DateTimeFieldElement.h:
+
+ Added base class implementations of setEmptyValue and setValueAsInteger
+ so that the logic to change the text color when a placeholder is visible
+ can be shared.
+
+ Changed visibleValue to no longer be a pure virtual method, as the
+ implementations in derived classes were very similar, and can be
+ abstracted. For this reason, the new placeholderValue pure virtual method
+ was added.
+
+ * html/shadow/DateTimeFieldElements.cpp:
+ (WebCore::DateTimeDayFieldElement::DateTimeDayFieldElement):
+ (WebCore::DateTimeHourFieldElement::DateTimeHourFieldElement):
+ (WebCore::DateTimeMeridiemFieldElement::DateTimeMeridiemFieldElement):
+ (WebCore::DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement):
+ (WebCore::DateTimeMinuteFieldElement::DateTimeMinuteFieldElement):
+ (WebCore::DateTimeMonthFieldElement::DateTimeMonthFieldElement):
+
+ Months are 0-indexed, so we add 1 to the value returned by month().
+
+ (WebCore::DateTimeSecondFieldElement::DateTimeSecondFieldElement):
+ (WebCore::DateTimeSymbolicMonthFieldElement::DateTimeSymbolicMonthFieldElement):
+ (WebCore::DateTimeYearFieldElement::DateTimeYearFieldElement):
+ * html/shadow/DateTimeNumericFieldElement.cpp:
+ (WebCore::DateTimeNumericFieldElement::DateTimeNumericFieldElement):
+ (WebCore::DateTimeNumericFieldElement::setEmptyValue):
+ (WebCore::DateTimeNumericFieldElement::setValueAsInteger):
+ (WebCore::DateTimeNumericFieldElement::placeholderValue const):
+ (WebCore::DateTimeNumericFieldElement::valueAsInteger const):
+ * html/shadow/DateTimeNumericFieldElement.h:
+ * html/shadow/DateTimeSymbolicFieldElement.cpp:
+ (WebCore::DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement):
+ (WebCore::DateTimeSymbolicFieldElement::setEmptyValue):
+ (WebCore::DateTimeSymbolicFieldElement::setValueAsInteger):
+ (WebCore::DateTimeSymbolicFieldElement::placeholderValue const):
+ (WebCore::DateTimeSymbolicFieldElement::valueAsInteger const):
+ * html/shadow/DateTimeSymbolicFieldElement.h:
+
2020-11-30 Zalan Bujtas <[email protected]>
[LFC][IFC] Remove redundant const ContainerBox& formattingContextRoot from LineBuilder c'tor
Modified: trunk/Source/WebCore/html/shadow/DateTimeEditElement.cpp (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeEditElement.cpp 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeEditElement.cpp 2020-11-30 16:35:19 UTC (rev 270245)
@@ -191,6 +191,7 @@
: HTMLDivElement(divTag, document)
, m_editControlOwner(makeWeakPtr(editControlOwner))
{
+ m_placeholderDate.setToCurrentLocalTime();
}
DateTimeEditElement::~DateTimeEditElement() = default;
@@ -363,6 +364,11 @@
return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom();
}
+const GregorianDateTime& DateTimeEditElement::placeholderDate() const
+{
+ return m_placeholderDate;
+}
+
void DateTimeEditElement::resetFields()
{
m_fields.shrink(0);
Modified: trunk/Source/WebCore/html/shadow/DateTimeEditElement.h (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeEditElement.h 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeEditElement.h 2020-11-30 16:35:19 UTC (rev 270245)
@@ -103,9 +103,11 @@
bool isFieldOwnerDisabled() const final;
bool isFieldOwnerReadOnly() const final;
AtomString localeIdentifier() const final;
+ const GregorianDateTime& placeholderDate() const final;
Vector<Ref<DateTimeFieldElement>, maximumNumberOfFields> m_fields;
WeakPtr<EditControlOwner> m_editControlOwner;
+ GregorianDateTime m_placeholderDate;
};
} // namespace WebCore
Modified: trunk/Source/WebCore/html/shadow/DateTimeFieldElement.cpp (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeFieldElement.cpp 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeFieldElement.cpp 2020-11-30 16:35:19 UTC (rev 270245)
@@ -29,6 +29,8 @@
#if ENABLE(DATE_AND_TIME_INPUT_TYPES)
+#include "CSSPropertyNames.h"
+#include "CSSValueKeywords.h"
#include "DateComponents.h"
#include "EventNames.h"
#include "HTMLNames.h"
@@ -158,6 +160,22 @@
return m_fieldOwner ? m_fieldOwner->localeIdentifier() : nullAtom();
}
+void DateTimeFieldElement::setEmptyValue(EventBehavior)
+{
+ setInlineStyleProperty(CSSPropertyColor, CSSValueDarkgray);
+}
+
+void DateTimeFieldElement::setValueAsInteger(int, EventBehavior)
+{
+ if (!hasValue())
+ removeInlineStyleProperty(CSSPropertyColor);
+}
+
+String DateTimeFieldElement::visibleValue() const
+{
+ return hasValue() ? value() : placeholderValue();
+}
+
void DateTimeFieldElement::updateVisibleValue(EventBehavior eventBehavior)
{
if (!firstChild())
@@ -165,11 +183,9 @@
auto& textNode = downcast<Text>(*firstChild());
String newVisibleValue = visibleValue();
- if (textNode.wholeText() == newVisibleValue)
- return;
+ if (textNode.wholeText() != newVisibleValue)
+ textNode.replaceWholeText(newVisibleValue);
- textNode.replaceWholeText(newVisibleValue);
-
if (eventBehavior == DispatchInputAndChangeEvents && m_fieldOwner)
m_fieldOwner->fieldValueChanged();
}
Modified: trunk/Source/WebCore/html/shadow/DateTimeFieldElement.h (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeFieldElement.h 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeFieldElement.h 2020-11-30 16:35:19 UTC (rev 270245)
@@ -30,6 +30,7 @@
#include "HTMLDivElement.h"
+#include <wtf/GregorianDateTime.h>
#include <wtf/WeakPtr.h>
namespace WebCore {
@@ -52,20 +53,24 @@
virtual bool isFieldOwnerDisabled() const = 0;
virtual bool isFieldOwnerReadOnly() const = 0;
virtual AtomString localeIdentifier() const = 0;
+ virtual const GregorianDateTime& placeholderDate() const = 0;
};
void defaultEventHandler(Event&) override;
bool isFocusable() const final;
+ String visibleValue() const;
+
+ virtual void setEmptyValue(EventBehavior = DispatchNoEvent);
+ virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent);
+
virtual bool hasValue() const = 0;
virtual void populateDateTimeFieldsState(DateTimeFieldsState&) = 0;
- virtual void setEmptyValue(EventBehavior = DispatchNoEvent) = 0;
virtual void setValueAsDate(const DateComponents&) = 0;
- virtual void setValueAsInteger(int, EventBehavior = DispatchNoEvent) = 0;
virtual void stepDown() = 0;
virtual void stepUp() = 0;
virtual String value() const = 0;
- virtual String visibleValue() const = 0;
+ virtual String placeholderValue() const = 0;
protected:
DateTimeFieldElement(Document&, FieldOwner&);
Modified: trunk/Source/WebCore/html/shadow/DateTimeFieldElements.cpp (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeFieldElements.cpp 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeFieldElements.cpp 2020-11-30 16:35:19 UTC (rev 270245)
@@ -38,7 +38,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeDayFieldElement);
DateTimeDayFieldElement::DateTimeDayFieldElement(Document& document, FieldOwner& fieldOwner)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(1, 31), "--"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(1, 31), fieldOwner.placeholderDate().monthDay())
{
}
@@ -64,7 +64,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeHourFieldElement);
DateTimeHourFieldElement::DateTimeHourFieldElement(Document& document, FieldOwner& fieldOwner, int minimum, int maximum)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(minimum, maximum), "--"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(minimum, maximum), (maximum >= 12) ? 12 : 11)
{
}
@@ -129,7 +129,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMeridiemFieldElement);
DateTimeMeridiemFieldElement::DateTimeMeridiemFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels)
- : DateTimeSymbolicFieldElement(document, fieldOwner, labels)
+ : DateTimeSymbolicFieldElement(document, fieldOwner, labels, labels.size() - 1)
{
}
@@ -155,7 +155,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMillisecondFieldElement);
DateTimeMillisecondFieldElement::DateTimeMillisecondFieldElement(Document& document, FieldOwner& fieldOwner)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 999), "---"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 999), 0)
{
}
@@ -181,7 +181,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMinuteFieldElement);
DateTimeMinuteFieldElement::DateTimeMinuteFieldElement(Document& document, FieldOwner& fieldOwner)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 59), "--"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 59), 30)
{
}
@@ -207,7 +207,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeMonthFieldElement);
DateTimeMonthFieldElement::DateTimeMonthFieldElement(Document& document, FieldOwner& fieldOwner)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(1, 12), "--"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(1, 12), fieldOwner.placeholderDate().month() + 1)
{
}
@@ -234,7 +234,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeSecondFieldElement);
DateTimeSecondFieldElement::DateTimeSecondFieldElement(Document& document, FieldOwner& fieldOwner)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 59), "--"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(0, 59), 0)
{
}
@@ -260,7 +260,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeSymbolicMonthFieldElement);
DateTimeSymbolicMonthFieldElement::DateTimeSymbolicMonthFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& labels)
- : DateTimeSymbolicFieldElement(document, fieldOwner, labels)
+ : DateTimeSymbolicFieldElement(document, fieldOwner, labels, fieldOwner.placeholderDate().month())
{
}
@@ -286,7 +286,7 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeYearFieldElement);
DateTimeYearFieldElement::DateTimeYearFieldElement(Document& document, FieldOwner& fieldOwner)
- : DateTimeNumericFieldElement(document, fieldOwner, Range(DateComponents::minimumYear(), DateComponents::maximumYear()), "----"_s)
+ : DateTimeNumericFieldElement(document, fieldOwner, Range(DateComponents::minimumYear(), DateComponents::maximumYear()), fieldOwner.placeholderDate().year())
{
}
Modified: trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.cpp 2020-11-30 16:35:19 UTC (rev 270245)
@@ -54,10 +54,10 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeNumericFieldElement);
-DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, const String& placeholder)
+DateTimeNumericFieldElement::DateTimeNumericFieldElement(Document& document, FieldOwner& fieldOwner, const Range& range, int placeholder)
: DateTimeFieldElement(document, fieldOwner)
, m_range(range)
- , m_placeholder(placeholder)
+ , m_placeholder(formatValue(placeholder))
{
}
@@ -115,6 +115,8 @@
void DateTimeNumericFieldElement::setEmptyValue(EventBehavior eventBehavior)
{
+ DateTimeFieldElement::setEmptyValue(eventBehavior);
+
m_value = 0;
m_hasValue = false;
m_typeAheadBuffer.clear();
@@ -123,6 +125,8 @@
void DateTimeNumericFieldElement::setValueAsInteger(int value, EventBehavior eventBehavior)
{
+ DateTimeFieldElement::setValueAsInteger(value, eventBehavior);
+
m_value = m_range.clampValue(value);
m_hasValue = true;
updateVisibleValue(eventBehavior);
@@ -155,14 +159,14 @@
return m_hasValue ? formatValue(m_value) : emptyString();
}
-int DateTimeNumericFieldElement::valueAsInteger() const
+String DateTimeNumericFieldElement::placeholderValue() const
{
- return m_hasValue ? m_value : -1;
+ return m_placeholder;
}
-String DateTimeNumericFieldElement::visibleValue() const
+int DateTimeNumericFieldElement::valueAsInteger() const
{
- return m_hasValue ? value() : m_placeholder;
+ return m_hasValue ? m_value : -1;
}
void DateTimeNumericFieldElement::handleKeyboardEvent(KeyboardEvent& keyboardEvent)
Modified: trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeNumericFieldElement.h 2020-11-30 16:35:19 UTC (rev 270245)
@@ -48,7 +48,7 @@
};
protected:
- DateTimeNumericFieldElement(Document&, FieldOwner&, const Range&, const String& placeholder);
+ DateTimeNumericFieldElement(Document&, FieldOwner&, const Range&, int placeholder);
int maximum() const;
@@ -60,7 +60,6 @@
void stepDown() final;
void stepUp() final;
int valueAsInteger() const final;
- String visibleValue() const final;
private:
Optional<Style::ElementStyle> resolveCustomStyle(const RenderStyle&, const RenderStyle*) final;
@@ -67,6 +66,7 @@
// DateTimeFieldElement functions:
String value() const final;
+ String placeholderValue() const final;
void handleKeyboardEvent(KeyboardEvent&) final;
void handleBlurEvent(Event&) final;
Modified: trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.cpp 2020-11-30 16:35:19 UTC (rev 270245)
@@ -41,18 +41,10 @@
WTF_MAKE_ISO_ALLOCATED_IMPL(DateTimeSymbolicFieldElement);
-static AtomString makeVisibleEmptyValue(const Vector<String>& symbols)
-{
- unsigned maximumLength = 0;
- for (auto& symbol : symbols)
- maximumLength = std::max(maximumLength, numGraphemeClusters(symbol));
- return makeString(pad('-', maximumLength, emptyString()));
-}
-
-DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& symbols)
+DateTimeSymbolicFieldElement::DateTimeSymbolicFieldElement(Document& document, FieldOwner& fieldOwner, const Vector<String>& symbols, int placeholderIndex)
: DateTimeFieldElement(document, fieldOwner)
, m_symbols(symbols)
- , m_visibleEmptyValue(makeVisibleEmptyValue(symbols))
+ , m_placeholderIndex(placeholderIndex)
, m_typeAhead(this)
{
ASSERT(!m_symbols.isEmpty());
@@ -86,6 +78,8 @@
void DateTimeSymbolicFieldElement::setEmptyValue(EventBehavior eventBehavior)
{
+ DateTimeFieldElement::setEmptyValue(eventBehavior);
+
m_selectedIndex = invalidIndex;
updateVisibleValue(eventBehavior);
}
@@ -92,6 +86,8 @@
void DateTimeSymbolicFieldElement::setValueAsInteger(int newSelectedIndex, EventBehavior eventBehavior)
{
+ DateTimeFieldElement::setValueAsInteger(newSelectedIndex, eventBehavior);
+
m_selectedIndex = std::max(0, std::min(newSelectedIndex, static_cast<int>(m_symbols.size() - 1)));
updateVisibleValue(eventBehavior);
}
@@ -117,21 +113,16 @@
return hasValue() ? m_symbols[m_selectedIndex] : emptyString();
}
-int DateTimeSymbolicFieldElement::valueAsInteger() const
+String DateTimeSymbolicFieldElement::placeholderValue() const
{
- return m_selectedIndex;
+ return m_symbols[m_placeholderIndex];
}
-String DateTimeSymbolicFieldElement::visibleEmptyValue() const
+int DateTimeSymbolicFieldElement::valueAsInteger() const
{
- return m_visibleEmptyValue;
+ return m_selectedIndex;
}
-String DateTimeSymbolicFieldElement::visibleValue() const
-{
- return hasValue() ? m_symbols[m_selectedIndex] : visibleEmptyValue();
-}
-
void DateTimeSymbolicFieldElement::handleKeyboardEvent(KeyboardEvent& keyboardEvent)
{
if (keyboardEvent.type() != eventNames().keypressEvent)
Modified: trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h (270244 => 270245)
--- trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h 2020-11-30 15:39:37 UTC (rev 270244)
+++ trunk/Source/WebCore/html/shadow/DateTimeSymbolicFieldElement.h 2020-11-30 16:35:19 UTC (rev 270245)
@@ -36,7 +36,7 @@
class DateTimeSymbolicFieldElement : public DateTimeFieldElement, public TypeAheadDataSource {
WTF_MAKE_ISO_ALLOCATED(DateTimeSymbolicFieldElement);
protected:
- DateTimeSymbolicFieldElement(Document&, FieldOwner&, const Vector<String>&);
+ DateTimeSymbolicFieldElement(Document&, FieldOwner&, const Vector<String>&, int);
size_t symbolsSize() const { return m_symbols.size(); }
bool hasValue() const final;
void initialize(const AtomString& pseudo);
@@ -49,13 +49,11 @@
Optional<Style::ElementStyle> resolveCustomStyle(const RenderStyle&, const RenderStyle*) final;
- String visibleEmptyValue() const;
-
// DateTimeFieldElement functions:
void stepDown() final;
void stepUp() final;
String value() const final;
- String visibleValue() const final;
+ String placeholderValue() const final;
void handleKeyboardEvent(KeyboardEvent&) final;
// TypeAheadDataSource functions:
@@ -64,10 +62,10 @@
String optionAtIndex(int index) const final;
const Vector<String> m_symbols;
+ int m_selectedIndex { invalidIndex };
+ int m_placeholderIndex { invalidIndex };
- const AtomString m_visibleEmptyValue;
TypeAhead m_typeAhead;
- int m_selectedIndex { invalidIndex };
};
} // namespace WebCore