2 * Copyright (C) 2012 Google Inc. All rights reserved.
4 * Redistribution and use in source and binary forms, with or without
5 * modification, are permitted provided that the following conditions
7 * 1. Redistributions of source code must retain the above copyright
8 * notice, this list of conditions and the following disclaimer.
9 * 2. Redistributions in binary form must reproduce the above copyright
10 * notice, this list of conditions and the following disclaimer in the
11 * documentation and/or other materials provided with the distribution.
13 * THIS SOFTWARE IS PROVIDED BY APPLE INC. AND ITS CONTRIBUTORS ``AS IS'' AND
14 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
15 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
16 * ARE DISCLAIMED. IN NO EVENT SHALL APPLE INC. OR ITS CONTRIBUTORS BE LIABLE
17 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
18 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
19 * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
20 * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
21 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
22 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
27 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
28 #include "core/html/shadow/DateTimeEditElement.h"
30 #include "HTMLNames.h"
31 #include "bindings/v8/ExceptionStatePlaceholder.h"
32 #include "core/dom/Text.h"
33 #include "core/events/MouseEvent.h"
34 #include "core/html/forms/DateTimeFieldsState.h"
35 #include "core/html/shadow/DateTimeFieldElements.h"
36 #include "core/html/shadow/ShadowElementNames.h"
37 #include "core/platform/graphics/FontCache.h"
38 #include "core/rendering/style/RenderStyle.h"
39 #include "core/rendering/style/StyleInheritedData.h"
40 #include "platform/DateComponents.h"
41 #include "platform/text/DateTimeFormat.h"
42 #include "platform/text/PlatformLocale.h"
43 #include "wtf/DateMath.h"
47 using namespace HTMLNames;
48 using namespace WTF::Unicode;
50 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
51 WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder);
54 // The argument objects must be alive until this object dies.
55 DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, const DateComponents&);
57 bool build(const String&);
60 bool needMillisecondField() const;
61 bool shouldAMPMFieldDisabled() const;
62 bool shouldDayOfMonthFieldDisabled() const;
63 bool shouldHourFieldDisabled() const;
64 bool shouldMillisecondFieldDisabled() const;
65 bool shouldMinuteFieldDisabled() const;
66 bool shouldSecondFieldDisabled() const;
67 bool shouldYearFieldDisabled() const;
68 inline const StepRange& stepRange() const { return m_parameters.stepRange; }
69 DateTimeNumericFieldElement::Step createStep(double msPerFieldUnit, double msPerFieldSize) const;
71 // DateTimeFormat::TokenHandler functions.
72 virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
73 virtual void visitLiteral(const String&) OVERRIDE FINAL;
75 DateTimeEditElement& m_editElement;
76 const DateComponents m_dateValue;
77 const DateTimeEditElement::LayoutParameters& m_parameters;
78 DateTimeNumericFieldElement::Range m_dayRange;
79 DateTimeNumericFieldElement::Range m_hour23Range;
80 DateTimeNumericFieldElement::Range m_minuteRange;
81 DateTimeNumericFieldElement::Range m_secondRange;
82 DateTimeNumericFieldElement::Range m_millisecondRange;
85 DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue)
86 : m_editElement(elemnt)
87 , m_dateValue(dateValue)
88 , m_parameters(layoutParameters)
90 , m_hour23Range(0, 23)
91 , m_minuteRange(0, 59)
92 , m_secondRange(0, 59)
93 , m_millisecondRange(0, 999)
95 if (m_dateValue.type() == DateComponents::Date || m_dateValue.type() == DateComponents::DateTimeLocal) {
96 if (m_parameters.minimum.type() != DateComponents::Invalid
97 && m_parameters.maximum.type() != DateComponents::Invalid
98 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
99 && m_parameters.minimum.month() == m_parameters.maximum.month()
100 && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) {
101 m_dayRange.minimum = m_parameters.minimum.monthDay();
102 m_dayRange.maximum = m_parameters.maximum.monthDay();
106 if (m_dateValue.type() == DateComponents::Time || m_dayRange.isSingleton()) {
107 if (m_parameters.minimum.type() != DateComponents::Invalid
108 && m_parameters.maximum.type() != DateComponents::Invalid
109 && m_parameters.minimum.hour() <= m_parameters.maximum.hour()) {
110 m_hour23Range.minimum = m_parameters.minimum.hour();
111 m_hour23Range.maximum = m_parameters.maximum.hour();
115 if (m_hour23Range.isSingleton() && m_parameters.minimum.minute() <= m_parameters.maximum.minute()) {
116 m_minuteRange.minimum = m_parameters.minimum.minute();
117 m_minuteRange.maximum = m_parameters.maximum.minute();
119 if (m_minuteRange.isSingleton() && m_parameters.minimum.second() <= m_parameters.maximum.second()) {
120 m_secondRange.minimum = m_parameters.minimum.second();
121 m_secondRange.maximum = m_parameters.maximum.second();
123 if (m_secondRange.isSingleton() && m_parameters.minimum.millisecond() <= m_parameters.maximum.millisecond()) {
124 m_millisecondRange.minimum = m_parameters.minimum.millisecond();
125 m_millisecondRange.maximum = m_parameters.maximum.millisecond();
129 bool DateTimeEditBuilder::build(const String& formatString)
131 m_editElement.resetFields();
132 return DateTimeFormat::parse(formatString, *this);
135 bool DateTimeEditBuilder::needMillisecondField() const
137 return m_dateValue.millisecond()
138 || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero()
139 || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero();
142 void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count)
144 const int countForAbbreviatedMonth = 3;
145 const int countForFullMonth = 4;
146 const int countForNarrowMonth = 5;
147 Document& document = m_editElement.document();
150 case DateTimeFormat::FieldTypeDayOfMonth: {
151 RefPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, m_dayRange);
152 m_editElement.addField(field);
153 if (shouldDayOfMonthFieldDisabled()) {
154 field->setValueAsDate(m_dateValue);
155 field->setDisabled();
160 case DateTimeFormat::FieldTypeHour11: {
161 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
162 RefPtr<DateTimeFieldElement> field = DateTimeHour11FieldElement::create(document, m_editElement, m_hour23Range, step);
163 m_editElement.addField(field);
164 if (shouldHourFieldDisabled()) {
165 field->setValueAsDate(m_dateValue);
166 field->setDisabled();
171 case DateTimeFormat::FieldTypeHour12: {
172 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerHour * 12);
173 RefPtr<DateTimeFieldElement> field = DateTimeHour12FieldElement::create(document, m_editElement, m_hour23Range, step);
174 m_editElement.addField(field);
175 if (shouldHourFieldDisabled()) {
176 field->setValueAsDate(m_dateValue);
177 field->setDisabled();
182 case DateTimeFormat::FieldTypeHour23: {
183 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
184 RefPtr<DateTimeFieldElement> field = DateTimeHour23FieldElement::create(document, m_editElement, m_hour23Range, step);
185 m_editElement.addField(field);
186 if (shouldHourFieldDisabled()) {
187 field->setValueAsDate(m_dateValue);
188 field->setDisabled();
193 case DateTimeFormat::FieldTypeHour24: {
194 DateTimeNumericFieldElement::Step step = createStep(msPerHour, msPerDay);
195 RefPtr<DateTimeFieldElement> field = DateTimeHour24FieldElement::create(document, m_editElement, m_hour23Range, step);
196 m_editElement.addField(field);
197 if (shouldHourFieldDisabled()) {
198 field->setValueAsDate(m_dateValue);
199 field->setDisabled();
204 case DateTimeFormat::FieldTypeMinute: {
205 DateTimeNumericFieldElement::Step step = createStep(msPerMinute, msPerHour);
206 RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, m_minuteRange, step);
207 m_editElement.addField(field);
208 if (shouldMinuteFieldDisabled()) {
209 field->setValueAsDate(m_dateValue);
210 field->setDisabled();
215 case DateTimeFormat::FieldTypeMonth: // Fallthrough.
216 case DateTimeFormat::FieldTypeMonthStandAlone: {
217 int minMonth = 0, maxMonth = 11;
218 if (m_parameters.minimum.type() != DateComponents::Invalid
219 && m_parameters.maximum.type() != DateComponents::Invalid
220 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
221 && m_parameters.minimum.month() <= m_parameters.maximum.month()) {
222 minMonth = m_parameters.minimum.month();
223 maxMonth = m_parameters.maximum.month();
225 RefPtr<DateTimeFieldElement> field;
227 case countForNarrowMonth: // Fallthrough.
228 case countForAbbreviatedMonth:
229 field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth);
231 case countForFullMonth:
232 field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth);
235 field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, DateTimeNumericFieldElement::Range(minMonth + 1, maxMonth + 1));
238 m_editElement.addField(field);
239 if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) {
240 field->setValueAsDate(m_dateValue);
241 field->setDisabled();
246 case DateTimeFormat::FieldTypePeriod: {
247 RefPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels());
248 m_editElement.addField(field);
249 if (shouldAMPMFieldDisabled()) {
250 field->setValueAsDate(m_dateValue);
251 field->setDisabled();
256 case DateTimeFormat::FieldTypeSecond: {
257 DateTimeNumericFieldElement::Step step = createStep(msPerSecond, msPerMinute);
258 RefPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, m_secondRange, step);
259 m_editElement.addField(field);
260 if (shouldSecondFieldDisabled()) {
261 field->setValueAsDate(m_dateValue);
262 field->setDisabled();
265 if (needMillisecondField()) {
266 visitLiteral(m_parameters.locale.localizedDecimalSeparator());
267 visitField(DateTimeFormat::FieldTypeFractionalSecond, 3);
272 case DateTimeFormat::FieldTypeFractionalSecond: {
273 DateTimeNumericFieldElement::Step step = createStep(1, msPerSecond);
274 RefPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, m_millisecondRange, step);
275 m_editElement.addField(field);
276 if (shouldMillisecondFieldDisabled()) {
277 field->setValueAsDate(m_dateValue);
278 field->setDisabled();
283 case DateTimeFormat::FieldTypeWeekOfYear: {
284 DateTimeNumericFieldElement::Range range(DateComponents::minimumWeekNumber, DateComponents::maximumWeekNumber);
285 if (m_parameters.minimum.type() != DateComponents::Invalid
286 && m_parameters.maximum.type() != DateComponents::Invalid
287 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
288 && m_parameters.minimum.week() <= m_parameters.maximum.week()) {
289 range.minimum = m_parameters.minimum.week();
290 range.maximum = m_parameters.maximum.week();
292 m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, range));
296 case DateTimeFormat::FieldTypeYear: {
297 DateTimeYearFieldElement::Parameters yearParams;
298 if (m_parameters.minimum.type() == DateComponents::Invalid) {
299 yearParams.minimumYear = DateComponents::minimumYear();
300 yearParams.minIsSpecified = false;
302 yearParams.minimumYear = m_parameters.minimum.fullYear();
303 yearParams.minIsSpecified = true;
305 if (m_parameters.maximum.type() == DateComponents::Invalid) {
306 yearParams.maximumYear = DateComponents::maximumYear();
307 yearParams.maxIsSpecified = false;
309 yearParams.maximumYear = m_parameters.maximum.fullYear();
310 yearParams.maxIsSpecified = true;
312 if (yearParams.minimumYear > yearParams.maximumYear) {
313 std::swap(yearParams.minimumYear, yearParams.maximumYear);
314 std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified);
316 yearParams.placeholder = m_parameters.placeholderForYear;
317 RefPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams);
318 m_editElement.addField(field);
319 if (shouldYearFieldDisabled()) {
320 field->setValueAsDate(m_dateValue);
321 field->setDisabled();
331 bool DateTimeEditBuilder::shouldAMPMFieldDisabled() const
333 return shouldHourFieldDisabled()
334 || (m_hour23Range.minimum < 12 && m_hour23Range.maximum < 12 && m_dateValue.hour() < 12)
335 || (m_hour23Range.minimum >= 12 && m_hour23Range.maximum >= 12 && m_dateValue.hour() >= 12);
338 bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled() const
340 return m_dayRange.isSingleton() && m_dayRange.minimum == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date;
343 bool DateTimeEditBuilder::shouldHourFieldDisabled() const
345 if (m_hour23Range.isSingleton() && m_hour23Range.minimum == m_dateValue.hour()
346 && !(shouldMinuteFieldDisabled() && shouldSecondFieldDisabled() && shouldMillisecondFieldDisabled()))
349 if (m_dateValue.type() == DateComponents::Time)
351 ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal);
353 if (shouldDayOfMonthFieldDisabled()) {
354 ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear());
355 ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month());
359 const Decimal decimalMsPerDay(static_cast<int>(msPerDay));
360 Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor();
361 return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero();
364 bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const
366 if (m_millisecondRange.isSingleton() && m_millisecondRange.minimum == m_dateValue.millisecond())
369 const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond));
370 return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero();
373 bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const
375 if (m_minuteRange.isSingleton() && m_minuteRange.minimum == m_dateValue.minute())
378 const Decimal decimalMsPerHour(static_cast<int>(msPerHour));
379 Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor();
380 return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero();
383 bool DateTimeEditBuilder::shouldSecondFieldDisabled() const
385 if (m_secondRange.isSingleton() && m_secondRange.minimum == m_dateValue.second())
388 const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute));
389 Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor();
390 return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero();
393 bool DateTimeEditBuilder::shouldYearFieldDisabled() const
395 return m_parameters.minimum.type() != DateComponents::Invalid
396 && m_parameters.maximum.type() != DateComponents::Invalid
397 && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
398 && m_parameters.minimum.fullYear() == m_dateValue.fullYear();
401 void DateTimeEditBuilder::visitLiteral(const String& text)
403 DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral));
404 ASSERT(text.length());
405 RefPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document());
406 element->setPart(textPseudoId);
407 if (m_parameters.locale.isRTL() && text.length()) {
408 Direction dir = direction(text[0]);
409 if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral)
410 element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1)));
412 element->appendChild(Text::create(m_editElement.document(), text));
413 m_editElement.fieldsWrapperElement()->appendChild(element);
416 DateTimeNumericFieldElement::Step DateTimeEditBuilder::createStep(double msPerFieldUnit, double msPerFieldSize) const
418 const Decimal msPerFieldUnitDecimal(static_cast<int>(msPerFieldUnit));
419 const Decimal msPerFieldSizeDecimal(static_cast<int>(msPerFieldSize));
420 Decimal stepMilliseconds = stepRange().step();
421 ASSERT(!msPerFieldUnitDecimal.isZero());
422 ASSERT(!msPerFieldSizeDecimal.isZero());
423 ASSERT(!stepMilliseconds.isZero());
425 DateTimeNumericFieldElement::Step step(1, 0);
427 if (stepMilliseconds.remainder(msPerFieldSizeDecimal).isZero())
428 stepMilliseconds = msPerFieldSizeDecimal;
430 if (msPerFieldSizeDecimal.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnitDecimal).isZero()) {
431 step.step = static_cast<int>((stepMilliseconds / msPerFieldUnitDecimal).toDouble());
432 step.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnitDecimal).floor().remainder(msPerFieldSizeDecimal / msPerFieldUnitDecimal).toDouble());
437 // ----------------------------
439 DateTimeEditElement::EditControlOwner::~EditControlOwner()
443 DateTimeEditElement::DateTimeEditElement(Document& document, EditControlOwner& editControlOwner)
444 : HTMLDivElement(divTag, document)
445 , m_editControlOwner(&editControlOwner)
447 setHasCustomStyleCallbacks();
450 DateTimeEditElement::~DateTimeEditElement()
452 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
453 m_fields[fieldIndex]->removeEventHandler();
456 inline Element* DateTimeEditElement::fieldsWrapperElement() const
458 ASSERT(firstChild());
459 return toElement(firstChild());
462 void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field)
464 if (m_fields.size() == m_fields.capacity())
466 m_fields.append(field.get());
467 fieldsWrapperElement()->appendChild(field);
470 bool DateTimeEditElement::anyEditableFieldsHaveValues() const
472 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
473 if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue())
479 void DateTimeEditElement::blurByOwner()
481 if (DateTimeFieldElement* field = focusedField())
485 PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document& document, EditControlOwner& editControlOwner)
487 RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner));
488 container->setPart(AtomicString("-webkit-datetime-edit", AtomicString::ConstructFromLiteral));
489 container->setAttribute(idAttr, ShadowElementNames::dateTimeEdit());
490 return container.release();
493 PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer()
495 // FIXME: This is a kind of layout. We might want to introduce new renderer.
496 FontCachePurgePreventer fontCachePurgePreventer;
497 RefPtr<RenderStyle> originalStyle = originalStyleForRenderer();
498 RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
500 for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) {
501 if (!child->isElementNode())
503 Element* childElement = toElement(child);
504 if (childElement->isDateTimeFieldElement()) {
505 // We need to pass the Font of this element because child elements
506 // can't resolve inherited style at this timing.
507 width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font());
509 // ::-webkit-datetime-edit-text case. It has no
510 // border/padding/margin in html.css.
511 width += style->font().width(childElement->textContent());
514 style->setWidth(Length(ceilf(width), Fixed));
516 return style.release();
519 void DateTimeEditElement::didBlurFromField()
521 if (m_editControlOwner)
522 m_editControlOwner->didBlurFromControl();
525 void DateTimeEditElement::didFocusOnField()
527 if (m_editControlOwner)
528 m_editControlOwner->didFocusOnControl();
531 void DateTimeEditElement::disabledStateChanged()
536 DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const
538 return fieldIndex < m_fields.size() ? m_fields[fieldIndex] : 0;
541 size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const
543 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
544 if (m_fields[fieldIndex] == &field)
547 return invalidFieldIndex;
550 void DateTimeEditElement::focusIfNoFocus()
552 if (focusedFieldIndex() != invalidFieldIndex)
554 focusOnNextFocusableField(0);
557 void DateTimeEditElement::focusByOwner(Element* oldFocusedElement)
559 if (oldFocusedElement && oldFocusedElement->isDateTimeFieldElement()) {
560 DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedElement);
561 size_t index = fieldIndexOf(*oldFocusedField);
562 if (index != invalidFieldIndex && oldFocusedField->isFocusable()) {
563 oldFocusedField->focus();
567 focusOnNextFocusableField(0);
570 DateTimeFieldElement* DateTimeEditElement::focusedField() const
572 return fieldAt(focusedFieldIndex());
575 size_t DateTimeEditElement::focusedFieldIndex() const
577 Element* const focusedFieldElement = document().focusedElement();
578 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
579 if (m_fields[fieldIndex] == focusedFieldElement)
582 return invalidFieldIndex;
585 void DateTimeEditElement::fieldValueChanged()
587 if (m_editControlOwner)
588 m_editControlOwner->editControlValueChanged();
591 bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex)
593 for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) {
594 if (m_fields[fieldIndex]->isFocusable()) {
595 m_fields[fieldIndex]->focus();
602 bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field)
604 const size_t startFieldIndex = fieldIndexOf(field);
605 if (startFieldIndex == invalidFieldIndex)
607 return focusOnNextFocusableField(startFieldIndex + 1);
610 bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field)
612 const size_t startFieldIndex = fieldIndexOf(field);
613 if (startFieldIndex == invalidFieldIndex)
615 size_t fieldIndex = startFieldIndex;
616 while (fieldIndex > 0) {
618 if (m_fields[fieldIndex]->isFocusable()) {
619 m_fields[fieldIndex]->focus();
626 bool DateTimeEditElement::isDateTimeEditElement() const
631 bool DateTimeEditElement::isDisabled() const
633 return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled();
636 bool DateTimeEditElement::isFieldOwnerDisabled() const
641 bool DateTimeEditElement::isFieldOwnerReadOnly() const
646 bool DateTimeEditElement::isReadOnly() const
648 return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly();
651 void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue)
653 DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral));
655 RefPtr<HTMLDivElement> element = HTMLDivElement::create(document());
656 element->setPart(fieldsWrapperPseudoId);
657 appendChild(element.get());
659 Element* fieldsWrapper = fieldsWrapperElement();
661 size_t focusedFieldIndex = this->focusedFieldIndex();
662 DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex);
663 const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom;
665 DateTimeEditBuilder builder(*this, layoutParameters, dateValue);
666 Node* lastChildToBeRemoved = fieldsWrapper->lastChild();
667 if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) {
668 lastChildToBeRemoved = fieldsWrapper->lastChild();
669 builder.build(layoutParameters.fallbackDateTimeFormat);
672 if (focusedFieldIndex != invalidFieldIndex) {
673 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
674 if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) {
675 focusedFieldIndex = fieldIndex;
679 if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1)))
683 if (lastChildToBeRemoved) {
684 for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) {
685 fieldsWrapper->removeChild(childNode);
686 if (childNode == lastChildToBeRemoved)
689 setNeedsStyleRecalc();
693 AtomicString DateTimeEditElement::localeIdentifier() const
695 return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom;
698 void DateTimeEditElement::readOnlyStateChanged()
703 void DateTimeEditElement::resetFields()
705 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
706 m_fields[fieldIndex]->removeEventHandler();
710 void DateTimeEditElement::defaultEventHandler(Event* event)
712 // In case of control owner forward event to control, e.g. DOM
713 // dispatchEvent method.
714 if (DateTimeFieldElement* field = focusedField()) {
715 field->defaultEventHandler(event);
716 if (event->defaultHandled())
720 HTMLDivElement::defaultEventHandler(event);
723 void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date)
725 layout(layoutParameters, date);
726 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
727 m_fields[fieldIndex]->setValueAsDate(date);
730 void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
732 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
733 m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState);
736 void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField)
738 layout(layoutParameters, dateForReadOnlyField);
739 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
740 m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent);
743 bool DateTimeEditElement::hasFocusedField()
745 return focusedFieldIndex() != invalidFieldIndex;
748 void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date)
750 ASSERT(date.type() == DateComponents::Date);
752 if (!m_editControlOwner)
755 DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState();
756 dateTimeFieldsState.setYear(date.fullYear());
757 dateTimeFieldsState.setMonth(date.month() + 1);
758 dateTimeFieldsState.setDayOfMonth(date.monthDay());
759 setValueAsDateTimeFieldsState(dateTimeFieldsState);
760 m_editControlOwner->editControlValueChanged();
763 void DateTimeEditElement::stepDown()
765 if (DateTimeFieldElement* const field = focusedField())
769 void DateTimeEditElement::stepUp()
771 if (DateTimeFieldElement* const field = focusedField())
775 void DateTimeEditElement::updateUIState()
778 if (DateTimeFieldElement* field = focusedField())
783 String DateTimeEditElement::value() const
785 if (!m_editControlOwner)
786 return emptyString();
787 return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState());
790 DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const
792 DateTimeFieldsState dateTimeFieldsState;
793 for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
794 m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState);
795 return dateTimeFieldsState;
798 } // namespace WebCore