4921eb02184909cc98ddf1ea606ea0ab74b547fb
[WebKit-https.git] / Source / WebCore / html / shadow / DateTimeEditElement.cpp
1 /*
2  * Copyright (C) 2012 Google Inc. All rights reserved.
3  *
4  * Redistribution and use in source and binary forms, with or without
5  * modification, are permitted provided that the following conditions
6  * are met:
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.
12  *
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
23  * SUCH DAMAGE.
24  */
25
26 #include "config.h"
27 #if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
28 #include "DateTimeEditElement.h"
29
30 #include "DateComponents.h"
31 #include "DateTimeFieldElements.h"
32 #include "DateTimeFieldsState.h"
33 #include "DateTimeFormat.h"
34 #include "DateTimeSymbolicFieldElement.h"
35 #include "EventHandler.h"
36 #include "FontCache.h"
37 #include "HTMLNames.h"
38 #include "KeyboardEvent.h"
39 #include "MouseEvent.h"
40 #include "PlatformLocale.h"
41 #include "RenderStyle.h"
42 #include "StyleResolver.h"
43 #include "Text.h"
44 #include <wtf/DateMath.h>
45 #include <wtf/text/StringBuilder.h>
46
47 namespace WebCore {
48
49 using namespace HTMLNames;
50 using namespace WTF::Unicode;
51
52 class DateTimeEditBuilder : private DateTimeFormat::TokenHandler {
53     WTF_MAKE_NONCOPYABLE(DateTimeEditBuilder);
54
55 public:
56     // The argument objects must be alive until this object dies.
57     DateTimeEditBuilder(DateTimeEditElement&, const DateTimeEditElement::LayoutParameters&, const DateComponents&);
58
59     bool build(const String&);
60
61 private:
62     void getRangeOfDayOfMonthField(int& minDay, int& maxDay) const;
63     bool needMillisecondField() const;
64     bool shouldDayOfMonthFieldDisabled(int minDay, int maxDay) const;
65     bool shouldHourFieldDisabled() const;
66     bool shouldMillisecondFieldDisabled() const;
67     bool shouldMinuteFieldDisabled() const;
68     bool shouldSecondFieldDisabled() const;
69     bool shouldYearFieldDisabled() const;
70     inline const StepRange& stepRange() const { return m_parameters.stepRange; }
71     DateTimeNumericFieldElement::Parameters createNumericFieldParameters(const Decimal& msPerFieldUnit, const Decimal& msPerFieldSize) const;
72
73     // DateTimeFormat::TokenHandler functions.
74     virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
75     virtual void visitLiteral(const String&) OVERRIDE FINAL;
76
77     DateTimeEditElement& m_editElement;
78     const DateComponents m_dateValue;
79     const DateTimeEditElement::LayoutParameters& m_parameters;
80 };
81
82 DateTimeEditBuilder::DateTimeEditBuilder(DateTimeEditElement& elemnt, const DateTimeEditElement::LayoutParameters& layoutParameters, const DateComponents& dateValue)
83     : m_editElement(elemnt)
84     , m_dateValue(dateValue)
85     , m_parameters(layoutParameters)
86 {
87 }
88
89 bool DateTimeEditBuilder::build(const String& formatString)
90 {
91     m_editElement.resetFields();
92     return DateTimeFormat::parse(formatString, *this);
93 }
94
95 void DateTimeEditBuilder::getRangeOfDayOfMonthField(int& minDay, int& maxDay) const
96 {
97     minDay = 1;
98     maxDay = 31;
99     if (m_parameters.minimum.type() != DateComponents::Invalid
100         && m_parameters.maximum.type() != DateComponents::Invalid
101         && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
102         && m_parameters.minimum.month() == m_parameters.maximum.month()
103         && m_parameters.minimum.monthDay() <= m_parameters.maximum.monthDay()) {
104         minDay = m_parameters.minimum.monthDay();
105         maxDay = m_parameters.maximum.monthDay();
106     }
107 }
108
109 bool DateTimeEditBuilder::needMillisecondField() const
110 {
111     return m_dateValue.millisecond()
112         || !stepRange().minimum().remainder(static_cast<int>(msPerSecond)).isZero()
113         || !stepRange().step().remainder(static_cast<int>(msPerSecond)).isZero();
114 }
115
116 void DateTimeEditBuilder::visitField(DateTimeFormat::FieldType fieldType, int count)
117 {
118     const int countForAbbreviatedMonth = 3;
119     const int countForFullMonth = 4;
120     const int countForNarrowMonth = 5;
121     Document* const document = m_editElement.document();
122
123     switch (fieldType) {
124     case DateTimeFormat::FieldTypeDayOfMonth: {
125         int minDay, maxDay;
126         getRangeOfDayOfMonthField(minDay, maxDay);
127         RefPtr<DateTimeFieldElement> field = DateTimeDayFieldElement::create(document, m_editElement, m_parameters.placeholderForDay, minDay, maxDay);
128         m_editElement.addField(field);
129         if (shouldDayOfMonthFieldDisabled(minDay, maxDay)) {
130             field->setValueAsDate(m_dateValue);
131             field->setDisabled();
132         }
133         return;
134     }
135
136     case DateTimeFormat::FieldTypeHour11: {
137         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(static_cast<int>(msPerHour), static_cast<int>(msPerHour * 12));
138         RefPtr<DateTimeFieldElement> field = DateTimeHourFieldElement::create(document, m_editElement, 0, 11, parameters);
139         m_editElement.addField(field);
140         if (shouldHourFieldDisabled()) {
141             field->setValueAsDate(m_dateValue);
142             field->setDisabled();
143         }
144         return;
145     }
146
147     case DateTimeFormat::FieldTypeHour12: {
148         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(static_cast<int>(msPerHour), static_cast<int>(msPerHour * 12));
149         RefPtr<DateTimeFieldElement> field = DateTimeHourFieldElement::create(document, m_editElement, 1, 12, parameters);
150         m_editElement.addField(field);
151         if (shouldHourFieldDisabled()) {
152             field->setValueAsDate(m_dateValue);
153             field->setDisabled();
154         }
155         return;
156     }
157
158     case DateTimeFormat::FieldTypeHour23: {
159         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(static_cast<int>(msPerHour), static_cast<int>(msPerDay));
160         RefPtr<DateTimeFieldElement> field = DateTimeHourFieldElement::create(document, m_editElement, 0, 23, parameters);
161         m_editElement.addField(field);
162         if (shouldHourFieldDisabled()) {
163             field->setValueAsDate(m_dateValue);
164             field->setDisabled();
165         }
166         return;
167     }
168
169     case DateTimeFormat::FieldTypeHour24: {
170         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(static_cast<int>(msPerHour), static_cast<int>(msPerDay));
171         RefPtr<DateTimeFieldElement> field = DateTimeHourFieldElement::create(document, m_editElement, 1, 24, parameters);
172         m_editElement.addField(field);
173         if (shouldHourFieldDisabled()) {
174             field->setValueAsDate(m_dateValue);
175             field->setDisabled();
176         }
177         return;
178     }
179
180     case DateTimeFormat::FieldTypeMinute: {
181         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(static_cast<int>(msPerMinute), static_cast<int>(msPerHour));
182         RefPtr<DateTimeNumericFieldElement> field = DateTimeMinuteFieldElement::create(document, m_editElement, parameters);
183         m_editElement.addField(field);
184         if (shouldMinuteFieldDisabled()) {
185             field->setValueAsDate(m_dateValue);
186             field->setDisabled();
187         }
188         return;
189     }
190
191     case DateTimeFormat::FieldTypeMonth: // Fallthrough.
192     case DateTimeFormat::FieldTypeMonthStandAlone: {
193         int minMonth = 0, maxMonth = 11;
194         if (m_parameters.minimum.type() != DateComponents::Invalid
195             && m_parameters.maximum.type() != DateComponents::Invalid
196             && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
197             && m_parameters.minimum.month() <= m_parameters.maximum.month()) {
198             minMonth = m_parameters.minimum.month();
199             maxMonth = m_parameters.maximum.month();
200         }
201         RefPtr<DateTimeFieldElement> field;
202         switch (count) {
203         case countForNarrowMonth: // Fallthrough.
204         case countForAbbreviatedMonth:
205             field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.shortMonthLabels() : m_parameters.locale.shortStandAloneMonthLabels(), minMonth, maxMonth);
206             break;
207         case countForFullMonth:
208             field = DateTimeSymbolicMonthFieldElement::create(document, m_editElement, fieldType == DateTimeFormat::FieldTypeMonth ? m_parameters.locale.monthLabels() : m_parameters.locale.standAloneMonthLabels(), minMonth, maxMonth);
209             break;
210         default:
211             field = DateTimeMonthFieldElement::create(document, m_editElement, m_parameters.placeholderForMonth, minMonth + 1, maxMonth + 1);
212             break;
213         }
214         m_editElement.addField(field);
215         if (minMonth == maxMonth && minMonth == m_dateValue.month() && m_dateValue.type() != DateComponents::Month) {
216             field->setValueAsDate(m_dateValue);
217             field->setDisabled();
218         }
219         return;
220     }
221
222     case DateTimeFormat::FieldTypePeriod: {
223         RefPtr<DateTimeFieldElement> field = DateTimeAMPMFieldElement::create(document, m_editElement, m_parameters.locale.timeAMPMLabels());
224         m_editElement.addField(field);
225         if (shouldHourFieldDisabled()) {
226             field->setValueAsDate(m_dateValue);
227             field->setDisabled();
228         }
229         return;
230     }
231
232     case DateTimeFormat::FieldTypeSecond: {
233         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(static_cast<int>(msPerSecond), static_cast<int>(msPerMinute));
234         RefPtr<DateTimeNumericFieldElement> field = DateTimeSecondFieldElement::create(document, m_editElement, parameters);
235         m_editElement.addField(field);
236         if (shouldSecondFieldDisabled()) {
237             field->setValueAsDate(m_dateValue);
238             field->setDisabled();
239         }
240
241         if (needMillisecondField()) {
242             visitLiteral(m_parameters.locale.localizedDecimalSeparator());
243             visitField(DateTimeFormat::FieldTypeFractionalSecond, 3);
244         }
245         return;
246     }
247
248     case DateTimeFormat::FieldTypeFractionalSecond: {
249         DateTimeNumericFieldElement::Parameters parameters = createNumericFieldParameters(1, static_cast<int>(msPerSecond));
250         RefPtr<DateTimeNumericFieldElement> field = DateTimeMillisecondFieldElement::create(document, m_editElement, parameters);
251         m_editElement.addField(field);
252         if (shouldMillisecondFieldDisabled()) {
253             field->setValueAsDate(m_dateValue);
254             field->setDisabled();
255         }
256         return;
257     }
258
259     case DateTimeFormat::FieldTypeWeekOfYear: {
260         int minWeek = DateComponents::minimumWeekNumber;
261         int maxWeek = DateComponents::maximumWeekNumber;
262         if (m_parameters.minimum.type() != DateComponents::Invalid
263             && m_parameters.maximum.type() != DateComponents::Invalid
264             && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
265             && m_parameters.minimum.week() <= m_parameters.maximum.week()) {
266             minWeek = m_parameters.minimum.week();
267             maxWeek = m_parameters.maximum.week();
268         }
269         m_editElement.addField(DateTimeWeekFieldElement::create(document, m_editElement, minWeek, maxWeek));
270         return;
271     }
272
273     case DateTimeFormat::FieldTypeYear: {
274         DateTimeYearFieldElement::Parameters yearParams;
275         if (m_parameters.minimum.type() == DateComponents::Invalid) {
276             yearParams.minimumYear = DateComponents::minimumYear();
277             yearParams.minIsSpecified = false;
278         } else {
279             yearParams.minimumYear = m_parameters.minimum.fullYear();
280             yearParams.minIsSpecified = true;
281         }
282         if (m_parameters.maximum.type() == DateComponents::Invalid) {
283             yearParams.maximumYear = DateComponents::maximumYear();
284             yearParams.maxIsSpecified = false;
285         } else {
286             yearParams.maximumYear = m_parameters.maximum.fullYear();
287             yearParams.maxIsSpecified = true;
288         }
289         if (yearParams.minimumYear > yearParams.maximumYear) {
290             std::swap(yearParams.minimumYear, yearParams.maximumYear);
291             std::swap(yearParams.minIsSpecified, yearParams.maxIsSpecified);
292         }
293         yearParams.placeholder = m_parameters.placeholderForYear;
294         RefPtr<DateTimeFieldElement> field = DateTimeYearFieldElement::create(document, m_editElement, yearParams);
295         m_editElement.addField(field);
296         if (shouldYearFieldDisabled()) {
297             field->setValueAsDate(m_dateValue);
298             field->setDisabled();
299         }
300         return;
301     }
302
303     default:
304         return;
305     }
306 }
307
308 bool DateTimeEditBuilder::shouldDayOfMonthFieldDisabled(int minDay, int maxDay) const
309 {
310     return minDay == maxDay && minDay == m_dateValue.monthDay() && m_dateValue.type() != DateComponents::Date;
311 }
312
313 bool DateTimeEditBuilder::shouldHourFieldDisabled() const
314 {
315     if (m_dateValue.type() == DateComponents::Time)
316         return false;
317     ASSERT(m_dateValue.type() == DateComponents::DateTimeLocal || m_dateValue.type() == DateComponents::DateTime);
318     int minDay, maxDay;
319     getRangeOfDayOfMonthField(minDay, maxDay);
320     if (shouldDayOfMonthFieldDisabled(minDay, maxDay)) {
321         ASSERT(m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear());
322         ASSERT(m_parameters.minimum.month() == m_parameters.maximum.month());
323         return false;
324     }
325
326     const Decimal decimalMsPerDay(static_cast<int>(msPerDay));
327     Decimal hourPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerDay) / static_cast<int>(msPerHour)).floor();
328     return hourPartOfMinimum == m_dateValue.hour() && stepRange().step().remainder(decimalMsPerDay).isZero();
329 }
330
331 bool DateTimeEditBuilder::shouldMillisecondFieldDisabled() const
332 {
333     const Decimal decimalMsPerSecond(static_cast<int>(msPerSecond));
334     return stepRange().minimum().abs().remainder(decimalMsPerSecond) == m_dateValue.millisecond() && stepRange().step().remainder(decimalMsPerSecond).isZero();
335 }
336
337 bool DateTimeEditBuilder::shouldMinuteFieldDisabled() const
338 {
339     const Decimal decimalMsPerHour(static_cast<int>(msPerHour));
340     Decimal minutePartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerHour) / static_cast<int>(msPerMinute)).floor();
341     return minutePartOfMinimum == m_dateValue.minute() && stepRange().step().remainder(decimalMsPerHour).isZero();
342 }
343
344 bool DateTimeEditBuilder::shouldSecondFieldDisabled() const
345 {
346     const Decimal decimalMsPerMinute(static_cast<int>(msPerMinute));
347     Decimal secondPartOfMinimum = (stepRange().minimum().abs().remainder(decimalMsPerMinute) / static_cast<int>(msPerSecond)).floor();
348     return secondPartOfMinimum == m_dateValue.second() && stepRange().step().remainder(decimalMsPerMinute).isZero();
349 }
350
351 bool DateTimeEditBuilder::shouldYearFieldDisabled() const
352 {
353     return m_parameters.minimum.type() != DateComponents::Invalid
354         && m_parameters.maximum.type() != DateComponents::Invalid
355         && m_parameters.minimum.fullYear() == m_parameters.maximum.fullYear()
356         && m_parameters.minimum.fullYear() == m_dateValue.fullYear();
357 }
358
359 void DateTimeEditBuilder::visitLiteral(const String& text)
360 {
361     DEFINE_STATIC_LOCAL(AtomicString, textPseudoId, ("-webkit-datetime-edit-text", AtomicString::ConstructFromLiteral));
362     ASSERT(text.length());
363     RefPtr<HTMLDivElement> element = HTMLDivElement::create(m_editElement.document());
364     element->setPseudo(textPseudoId);
365     if (m_parameters.locale.isRTL() && text.length()) {
366         Direction dir = direction(text[0]);
367         if (dir == SegmentSeparator || dir == WhiteSpaceNeutral || dir == OtherNeutral)
368             element->appendChild(Text::create(m_editElement.document(), String(&rightToLeftMark, 1)));
369     }
370     element->appendChild(Text::create(m_editElement.document(), text));
371     m_editElement.fieldsWrapperElement()->appendChild(element);
372 }
373
374 DateTimeNumericFieldElement::Parameters DateTimeEditBuilder::createNumericFieldParameters(const Decimal& msPerFieldUnit, const Decimal& msPerFieldSize) const
375 {
376     ASSERT(!msPerFieldUnit.isZero());
377     ASSERT(!msPerFieldSize.isZero());
378     Decimal stepMilliseconds = stepRange().step();
379     ASSERT(!stepMilliseconds.isZero());
380
381     DateTimeNumericFieldElement::Parameters parameters(1, 0);
382
383     if (stepMilliseconds.remainder(msPerFieldSize).isZero())
384         stepMilliseconds = msPerFieldSize;
385
386     if (msPerFieldSize.remainder(stepMilliseconds).isZero() && stepMilliseconds.remainder(msPerFieldUnit).isZero()) {
387         parameters.step = static_cast<int>((stepMilliseconds / msPerFieldUnit).toDouble());
388         parameters.stepBase = static_cast<int>((stepRange().stepBase() / msPerFieldUnit).floor().remainder(msPerFieldSize / msPerFieldUnit).toDouble());
389     }
390     return parameters;
391 }
392
393 // ----------------------------
394
395 DateTimeEditElement::EditControlOwner::~EditControlOwner()
396 {
397 }
398
399 DateTimeEditElement::DateTimeEditElement(Document* document, EditControlOwner& editControlOwner)
400     : HTMLDivElement(divTag, document)
401     , m_editControlOwner(&editControlOwner)
402 {
403     DEFINE_STATIC_LOCAL(AtomicString, dateTimeEditPseudoId, ("-webkit-datetime-edit", AtomicString::ConstructFromLiteral));
404     setPseudo(dateTimeEditPseudoId);
405     setHasCustomStyleCallbacks();
406 }
407
408 DateTimeEditElement::~DateTimeEditElement()
409 {
410     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
411         m_fields[fieldIndex]->removeEventHandler();
412 }
413
414 inline Element* DateTimeEditElement::fieldsWrapperElement() const
415 {
416     ASSERT(firstChild());
417     return toElement(firstChild());
418 }
419
420 void DateTimeEditElement::addField(PassRefPtr<DateTimeFieldElement> field)
421 {
422     if (m_fields.size() == m_fields.capacity())
423         return;
424     m_fields.append(field.get());
425     fieldsWrapperElement()->appendChild(field);
426 }
427
428 bool DateTimeEditElement::anyEditableFieldsHaveValues() const
429 {
430     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
431         if (!m_fields[fieldIndex]->isDisabled() && m_fields[fieldIndex]->hasValue())
432             return true;
433     }
434     return false;
435 }
436
437 void DateTimeEditElement::blurByOwner()
438 {
439     if (DateTimeFieldElement* field = focusedField())
440         field->blur();
441 }
442
443 PassRefPtr<DateTimeEditElement> DateTimeEditElement::create(Document* document, EditControlOwner& editControlOwner)
444 {
445     RefPtr<DateTimeEditElement> container = adoptRef(new DateTimeEditElement(document, editControlOwner));
446     return container.release();
447 }
448
449 PassRefPtr<RenderStyle> DateTimeEditElement::customStyleForRenderer()
450 {
451     // FIXME: This is a kind of layout. We might want to introduce new renderer.
452     FontCachePurgePreventer fontCachePurgePreventer;
453     RefPtr<RenderStyle> originalStyle = document()->styleResolver()->styleForElement(this);
454     RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
455     float width = 0;
456     for (Node* child = fieldsWrapperElement()->firstChild(); child; child = child->nextSibling()) {
457         if (!child->isElementNode())
458             continue;
459         Element* childElement = toElement(child);
460         if (childElement->isDateTimeFieldElement()) {
461             // We need to pass the Font of this element because child elements
462             // can't resolve inherited style at this timing.
463             width += static_cast<DateTimeFieldElement*>(childElement)->maximumWidth(style->font());
464         } else {
465             // ::-webkit-datetime-edit-text case. It has no
466             // border/padding/margin in html.css.
467             width += style->font().width(childElement->textContent());
468         }
469     }
470     style->setWidth(Length(ceilf(width), Fixed));
471     return style.release();
472 }
473
474 void DateTimeEditElement::didBlurFromField()
475 {
476     if (m_editControlOwner)
477         m_editControlOwner->didBlurFromControl();
478 }
479
480 void DateTimeEditElement::didFocusOnField()
481 {
482     if (m_editControlOwner)
483         m_editControlOwner->didFocusOnControl();
484 }
485
486 void DateTimeEditElement::disabledStateChanged()
487 {
488     updateUIState();
489 }
490
491 DateTimeFieldElement* DateTimeEditElement::fieldAt(size_t fieldIndex) const
492 {
493     return fieldIndex < m_fields.size() ? m_fields[fieldIndex] : 0;
494 }
495
496 size_t DateTimeEditElement::fieldIndexOf(const DateTimeFieldElement& field) const
497 {
498     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
499         if (m_fields[fieldIndex] == &field)
500             return fieldIndex;
501     }
502     return invalidFieldIndex;
503 }
504
505 void DateTimeEditElement::focusIfNoFocus()
506 {
507     if (focusedFieldIndex() != invalidFieldIndex)
508         return;
509     focusOnNextFocusableField(0);
510 }
511
512 void DateTimeEditElement::focusByOwner(Node* oldFocusedNode)
513 {
514     if (oldFocusedNode && oldFocusedNode->isElementNode() && toElement(oldFocusedNode)->isDateTimeFieldElement()) {
515         DateTimeFieldElement* oldFocusedField = static_cast<DateTimeFieldElement*>(oldFocusedNode);
516         size_t index = fieldIndexOf(*oldFocusedField);
517         if (index != invalidFieldIndex && oldFocusedField->isFocusable()) {
518             oldFocusedField->focus();
519             return;
520         }
521     }
522     focusOnNextFocusableField(0);
523 }
524
525 DateTimeFieldElement* DateTimeEditElement::focusedField() const
526 {
527     return fieldAt(focusedFieldIndex());
528 }
529
530 size_t DateTimeEditElement::focusedFieldIndex() const
531 {
532     Node* const focusedFieldNode = document()->focusedNode();
533     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
534         if (m_fields[fieldIndex] == focusedFieldNode)
535             return fieldIndex;
536     }
537     return invalidFieldIndex;
538 }
539
540 void DateTimeEditElement::fieldValueChanged()
541 {
542     if (m_editControlOwner)
543         m_editControlOwner->editControlValueChanged();
544 }
545
546 bool DateTimeEditElement::focusOnNextFocusableField(size_t startIndex)
547 {
548     for (size_t fieldIndex = startIndex; fieldIndex < m_fields.size(); ++fieldIndex) {
549         if (m_fields[fieldIndex]->isFocusable()) {
550             m_fields[fieldIndex]->focus();
551             return true;
552         }
553     }
554     return false;
555 }
556
557 bool DateTimeEditElement::focusOnNextField(const DateTimeFieldElement& field)
558 {
559     const size_t startFieldIndex = fieldIndexOf(field);
560     if (startFieldIndex == invalidFieldIndex)
561         return false;
562     return focusOnNextFocusableField(startFieldIndex + 1);
563 }
564
565 bool DateTimeEditElement::focusOnPreviousField(const DateTimeFieldElement& field)
566 {
567     const size_t startFieldIndex = fieldIndexOf(field);
568     if (startFieldIndex == invalidFieldIndex)
569         return false;
570     size_t fieldIndex = startFieldIndex;
571     while (fieldIndex > 0) {
572         --fieldIndex;
573         if (m_fields[fieldIndex]->isFocusable()) {
574             m_fields[fieldIndex]->focus();
575             return true;
576         }
577     }
578     return false;
579 }
580
581 bool DateTimeEditElement::isDisabled() const
582 {
583     return m_editControlOwner && m_editControlOwner->isEditControlOwnerDisabled();
584 }
585
586 bool DateTimeEditElement::isFieldOwnerDisabled() const
587 {
588     return isDisabled();
589 }
590
591 bool DateTimeEditElement::isFieldOwnerReadOnly() const
592 {
593     return isReadOnly();
594 }
595
596 bool DateTimeEditElement::isReadOnly() const
597 {
598     return m_editControlOwner && m_editControlOwner->isEditControlOwnerReadOnly();
599 }
600
601 void DateTimeEditElement::layout(const LayoutParameters& layoutParameters, const DateComponents& dateValue)
602 {
603     DEFINE_STATIC_LOCAL(AtomicString, fieldsWrapperPseudoId, ("-webkit-datetime-edit-fields-wrapper", AtomicString::ConstructFromLiteral));
604     if (!firstChild()) {
605         RefPtr<HTMLDivElement> element = HTMLDivElement::create(document());
606         element->setPseudo(fieldsWrapperPseudoId);
607         appendChild(element.get());
608     }
609     Element* fieldsWrapper = fieldsWrapperElement();
610
611     size_t focusedFieldIndex = this->focusedFieldIndex();
612     DateTimeFieldElement* const focusedField = fieldAt(focusedFieldIndex);
613     const AtomicString focusedFieldId = focusedField ? focusedField->shadowPseudoId() : nullAtom;
614
615     DateTimeEditBuilder builder(*this, layoutParameters, dateValue);
616     Node* lastChildToBeRemoved = fieldsWrapper->lastChild();
617     if (!builder.build(layoutParameters.dateTimeFormat) || m_fields.isEmpty()) {
618         lastChildToBeRemoved = fieldsWrapper->lastChild();
619         builder.build(layoutParameters.fallbackDateTimeFormat);
620     }
621
622     if (focusedFieldIndex != invalidFieldIndex) {
623         for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex) {
624             if (m_fields[fieldIndex]->shadowPseudoId() == focusedFieldId) {
625                 focusedFieldIndex = fieldIndex;
626                 break;
627             }
628         }
629         if (DateTimeFieldElement* field = fieldAt(std::min(focusedFieldIndex, m_fields.size() - 1)))
630             field->focus();
631     }
632
633     if (lastChildToBeRemoved) {
634         for (Node* childNode = fieldsWrapper->firstChild(); childNode; childNode = fieldsWrapper->firstChild()) {
635             fieldsWrapper->removeChild(childNode);
636             if (childNode == lastChildToBeRemoved)
637                 break;
638         }
639         setNeedsStyleRecalc();
640     }
641 }
642
643 AtomicString DateTimeEditElement::localeIdentifier() const
644 {
645     return m_editControlOwner ? m_editControlOwner->localeIdentifier() : nullAtom;
646 }
647
648 void DateTimeEditElement::readOnlyStateChanged()
649 {
650     updateUIState();
651 }
652
653 void DateTimeEditElement::resetFields()
654 {
655     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
656         m_fields[fieldIndex]->removeEventHandler();
657     m_fields.shrink(0);
658 }
659
660 void DateTimeEditElement::defaultEventHandler(Event* event)
661 {
662     // In case of control owner forward event to control, e.g. DOM
663     // dispatchEvent method.
664     if (DateTimeFieldElement* field = focusedField()) {
665         field->defaultEventHandler(event);
666         if (event->defaultHandled())
667             return;
668     }
669
670     HTMLDivElement::defaultEventHandler(event);
671 }
672
673 void DateTimeEditElement::setValueAsDate(const LayoutParameters& layoutParameters, const DateComponents& date)
674 {
675     layout(layoutParameters, date);
676     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
677         m_fields[fieldIndex]->setValueAsDate(date);
678 }
679
680 void DateTimeEditElement::setValueAsDateTimeFieldsState(const DateTimeFieldsState& dateTimeFieldsState)
681 {
682     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
683         m_fields[fieldIndex]->setValueAsDateTimeFieldsState(dateTimeFieldsState);
684 }
685
686 void DateTimeEditElement::setEmptyValue(const LayoutParameters& layoutParameters, const DateComponents& dateForReadOnlyField)
687 {
688     layout(layoutParameters, dateForReadOnlyField);
689     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
690         m_fields[fieldIndex]->setEmptyValue(DateTimeFieldElement::DispatchNoEvent);
691 }
692
693 bool DateTimeEditElement::hasFocusedField()
694 {
695     return focusedFieldIndex() != invalidFieldIndex;
696 }
697
698 void DateTimeEditElement::setOnlyYearMonthDay(const DateComponents& date)
699 {
700     ASSERT(date.type() == DateComponents::Date);
701
702     if (!m_editControlOwner)
703         return;
704
705     DateTimeFieldsState dateTimeFieldsState = valueAsDateTimeFieldsState();
706     dateTimeFieldsState.setYear(date.fullYear());
707     dateTimeFieldsState.setMonth(date.month() + 1);
708     dateTimeFieldsState.setDayOfMonth(date.monthDay());
709     setValueAsDateTimeFieldsState(dateTimeFieldsState);
710     m_editControlOwner->editControlValueChanged();
711 }
712
713 void DateTimeEditElement::stepDown()
714 {
715     if (DateTimeFieldElement* const field = focusedField())
716         field->stepDown();
717 }
718
719 void DateTimeEditElement::stepUp()
720 {
721     if (DateTimeFieldElement* const field = focusedField())
722         field->stepUp();
723 }
724
725 void DateTimeEditElement::updateUIState()
726 {
727     if (isDisabled()) {
728         if (DateTimeFieldElement* field = focusedField())
729             field->blur();
730     }
731 }
732
733 String DateTimeEditElement::value() const
734 {
735     if (!m_editControlOwner)
736         return emptyString();
737     return m_editControlOwner->formatDateTimeFieldsState(valueAsDateTimeFieldsState());
738 }
739
740 DateTimeFieldsState DateTimeEditElement::valueAsDateTimeFieldsState() const
741 {
742     DateTimeFieldsState dateTimeFieldsState;
743     for (size_t fieldIndex = 0; fieldIndex < m_fields.size(); ++fieldIndex)
744         m_fields[fieldIndex]->populateDateTimeFieldsState(dateTimeFieldsState);
745     return dateTimeFieldsState;
746 }
747
748 } // namespace WebCore
749
750 #endif