1/*
2 * Copyright (C) 2010 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 are
6 * met:
7 *
8 *     * Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 *     * Redistributions in binary form must reproduce the above
11 * copyright notice, this list of conditions and the following disclaimer
12 * in the documentation and/or other materials provided with the
13 * distribution.
14 *     * Neither the name of Google Inc. nor the names of its
15 * contributors may be used to endorse or promote products derived from
16 * this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
19 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
20 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
21 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
22 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
23 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
24 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
28 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31#include "config.h"
32#if ENABLE(INPUT_MULTIPLE_FIELDS_UI)
33#include "core/html/forms/BaseMultipleFieldsDateAndTimeInputType.h"
34
35#include "core/CSSValueKeywords.h"
36#include "core/dom/shadow/ShadowRoot.h"
37#include "core/events/KeyboardEvent.h"
38#include "core/events/ScopedEventQueue.h"
39#include "core/html/HTMLDataListElement.h"
40#include "core/html/HTMLInputElement.h"
41#include "core/html/HTMLOptionElement.h"
42#include "core/html/forms/DateTimeFieldsState.h"
43#include "core/html/forms/FormController.h"
44#include "core/html/shadow/ShadowElementNames.h"
45#include "core/page/FocusController.h"
46#include "core/page/Page.h"
47#include "core/rendering/RenderTheme.h"
48#include "platform/DateComponents.h"
49#include "platform/RuntimeEnabledFeatures.h"
50#include "platform/text/DateTimeFormat.h"
51#include "platform/text/PlatformLocale.h"
52#include "wtf/DateMath.h"
53
54namespace WebCore {
55
56class DateTimeFormatValidator : public DateTimeFormat::TokenHandler {
57public:
58    DateTimeFormatValidator()
59        : m_hasYear(false)
60        , m_hasMonth(false)
61        , m_hasWeek(false)
62        , m_hasDay(false)
63        , m_hasAMPM(false)
64        , m_hasHour(false)
65        , m_hasMinute(false)
66        , m_hasSecond(false) { }
67
68    virtual void visitField(DateTimeFormat::FieldType, int) OVERRIDE FINAL;
69    virtual void visitLiteral(const String&) OVERRIDE FINAL { }
70
71    bool validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType&);
72
73private:
74    bool m_hasYear;
75    bool m_hasMonth;
76    bool m_hasWeek;
77    bool m_hasDay;
78    bool m_hasAMPM;
79    bool m_hasHour;
80    bool m_hasMinute;
81    bool m_hasSecond;
82};
83
84void DateTimeFormatValidator::visitField(DateTimeFormat::FieldType fieldType, int)
85{
86    switch (fieldType) {
87    case DateTimeFormat::FieldTypeYear:
88        m_hasYear = true;
89        break;
90    case DateTimeFormat::FieldTypeMonth: // Fallthrough.
91    case DateTimeFormat::FieldTypeMonthStandAlone:
92        m_hasMonth = true;
93        break;
94    case DateTimeFormat::FieldTypeWeekOfYear:
95        m_hasWeek = true;
96        break;
97    case DateTimeFormat::FieldTypeDayOfMonth:
98        m_hasDay = true;
99        break;
100    case DateTimeFormat::FieldTypePeriod:
101        m_hasAMPM = true;
102        break;
103    case DateTimeFormat::FieldTypeHour11: // Fallthrough.
104    case DateTimeFormat::FieldTypeHour12:
105        m_hasHour = true;
106        break;
107    case DateTimeFormat::FieldTypeHour23: // Fallthrough.
108    case DateTimeFormat::FieldTypeHour24:
109        m_hasHour = true;
110        m_hasAMPM = true;
111        break;
112    case DateTimeFormat::FieldTypeMinute:
113        m_hasMinute = true;
114        break;
115    case DateTimeFormat::FieldTypeSecond:
116        m_hasSecond = true;
117        break;
118    default:
119        break;
120    }
121}
122
123bool DateTimeFormatValidator::validateFormat(const String& format, const BaseMultipleFieldsDateAndTimeInputType& inputType)
124{
125    if (!DateTimeFormat::parse(format, *this))
126        return false;
127    return inputType.isValidFormat(m_hasYear, m_hasMonth, m_hasWeek, m_hasDay, m_hasAMPM, m_hasHour, m_hasMinute, m_hasSecond);
128}
129
130DateTimeEditElement* BaseMultipleFieldsDateAndTimeInputType::dateTimeEditElement() const
131{
132    return toDateTimeEditElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::dateTimeEdit()));
133}
134
135SpinButtonElement* BaseMultipleFieldsDateAndTimeInputType::spinButtonElement() const
136{
137    return toSpinButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::spinButton()));
138}
139
140ClearButtonElement* BaseMultipleFieldsDateAndTimeInputType::clearButtonElement() const
141{
142    return toClearButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::clearButton()));
143}
144
145PickerIndicatorElement* BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorElement() const
146{
147    return toPickerIndicatorElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::pickerIndicator()));
148}
149
150inline bool BaseMultipleFieldsDateAndTimeInputType::containsFocusedShadowElement() const
151{
152    return element().userAgentShadowRoot()->contains(element().document().focusedElement());
153}
154
155void BaseMultipleFieldsDateAndTimeInputType::didBlurFromControl()
156{
157    // We don't need to call blur(). This function is called when control
158    // lost focus.
159
160    if (containsFocusedShadowElement())
161        return;
162    EventQueueScope scope;
163    RefPtrWillBeRawPtr<HTMLInputElement> protector(element());
164    // Remove focus ring by CSS "focus" pseudo class.
165    element().setFocus(false);
166    if (SpinButtonElement *spinButton = spinButtonElement())
167        spinButton->releaseCapture();
168}
169
170void BaseMultipleFieldsDateAndTimeInputType::didFocusOnControl()
171{
172    // We don't need to call focus(). This function is called when control
173    // got focus.
174
175    if (!containsFocusedShadowElement())
176        return;
177    // Add focus ring by CSS "focus" pseudo class.
178    // FIXME: Setting the focus flag to non-focused element is too tricky.
179    element().setFocus(true);
180}
181
182void BaseMultipleFieldsDateAndTimeInputType::editControlValueChanged()
183{
184    RefPtrWillBeRawPtr<HTMLInputElement> input(element());
185    String oldValue = input->value();
186    String newValue = sanitizeValue(dateTimeEditElement()->value());
187    // Even if oldValue is null and newValue is "", we should assume they are same.
188    if ((oldValue.isEmpty() && newValue.isEmpty()) || oldValue == newValue) {
189        input->setNeedsValidityCheck();
190    } else {
191        input->setValueInternal(newValue, DispatchNoEvent);
192        input->setNeedsStyleRecalc(SubtreeStyleChange);
193        input->dispatchFormControlInputEvent();
194    }
195    input->notifyFormStateChanged();
196    input->updateClearButtonVisibility();
197}
198
199bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const
200{
201    return false;
202}
203
204bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerDisabled() const
205{
206    return element().isDisabledFormControl();
207}
208
209bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerReadOnly() const
210{
211    return element().isReadOnly();
212}
213
214void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectSpinButtonOwner()
215{
216    if (DateTimeEditElement* edit = dateTimeEditElement())
217        edit->focusIfNoFocus();
218}
219
220bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToMouseEvents()
221{
222    return !element().isDisabledOrReadOnly();
223}
224
225bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToWheelEvents()
226{
227    if (!shouldSpinButtonRespondToMouseEvents())
228        return false;
229    if (DateTimeEditElement* edit = dateTimeEditElement())
230        return edit->hasFocusedField();
231    return false;
232}
233
234void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepDown()
235{
236    if (DateTimeEditElement* edit = dateTimeEditElement())
237        edit->stepDown();
238}
239
240void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepUp()
241{
242    if (DateTimeEditElement* edit = dateTimeEditElement())
243        edit->stepUp();
244}
245
246void BaseMultipleFieldsDateAndTimeInputType::spinButtonDidReleaseMouseCapture(SpinButtonElement::EventDispatch eventDispatch)
247{
248    if (eventDispatch == SpinButtonElement::EventDispatchAllowed)
249        element().dispatchFormControlChangeEvent();
250}
251
252bool BaseMultipleFieldsDateAndTimeInputType::isPickerIndicatorOwnerDisabledOrReadOnly() const
253{
254    return element().isDisabledOrReadOnly();
255}
256
257void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(const String& value)
258{
259    if (element().isValidValue(value)) {
260        element().setValue(value, DispatchInputAndChangeEvent);
261        return;
262    }
263
264    DateTimeEditElement* edit = this->dateTimeEditElement();
265    if (!edit)
266        return;
267    DateComponents date;
268    unsigned end;
269    if (date.parseDate(value, 0, end) && end == value.length())
270        edit->setOnlyYearMonthDay(date);
271    element().dispatchFormControlChangeEvent();
272}
273
274void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(double value)
275{
276    ASSERT(std::isfinite(value) || std::isnan(value));
277    if (std::isnan(value))
278        element().setValue(emptyString(), DispatchInputAndChangeEvent);
279    else
280        element().setValueAsNumber(value, ASSERT_NO_EXCEPTION, DispatchInputAndChangeEvent);
281}
282
283bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
284{
285    return element().setupDateTimeChooserParameters(parameters);
286}
287
288BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element)
289    : BaseDateAndTimeInputType(element)
290    , m_isDestroyingShadowSubtree(false)
291    , m_pickerIndicatorIsVisible(false)
292    , m_pickerIndicatorIsAlwaysVisible(false)
293{
294}
295
296BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType()
297{
298#if !ENABLE(OILPAN)
299    if (SpinButtonElement* element = spinButtonElement())
300        element->removeSpinButtonOwner();
301    if (ClearButtonElement* element = clearButtonElement())
302        element->removeClearButtonOwner();
303    if (DateTimeEditElement* element = dateTimeEditElement())
304        element->removeEditControlOwner();
305    if (PickerIndicatorElement* element = pickerIndicatorElement())
306        element->removePickerIndicatorOwner();
307#endif
308}
309
310String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
311{
312    return locale().queryString(blink::WebLocalizedString::ValidationBadInputForDateTime);
313}
314
315void BaseMultipleFieldsDateAndTimeInputType::blur()
316{
317    if (DateTimeEditElement* edit = dateTimeEditElement())
318        edit->blurByOwner();
319}
320
321PassRefPtr<RenderStyle> BaseMultipleFieldsDateAndTimeInputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)
322{
323    EDisplay originalDisplay = originalStyle->display();
324    EDisplay newDisplay = originalDisplay;
325    if (originalDisplay == INLINE || originalDisplay == INLINE_BLOCK)
326        newDisplay = INLINE_FLEX;
327    else if (originalDisplay == BLOCK)
328        newDisplay = FLEX;
329    TextDirection contentDirection = element().locale().isRTL() ? RTL : LTR;
330    if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay)
331        return originalStyle;
332
333    RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
334    style->setDirection(contentDirection);
335    style->setDisplay(newDisplay);
336    style->setUnique();
337    return style.release();
338}
339
340void BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree()
341{
342    ASSERT(element().shadow());
343
344    // Element must not have a renderer here, because if it did
345    // DateTimeEditElement::customStyleForRenderer() is called in appendChild()
346    // before the field wrapper element is created.
347    // FIXME: This code should not depend on such craziness.
348    ASSERT(!element().renderer());
349
350    Document& document = element().document();
351    ContainerNode* container = element().userAgentShadowRoot();
352
353    container->appendChild(DateTimeEditElement::create(document, *this));
354    element().updateView();
355    container->appendChild(ClearButtonElement::create(document, *this));
356    container->appendChild(SpinButtonElement::create(document, *this));
357
358    if (RenderTheme::theme().supportsCalendarPicker(formControlType()))
359        m_pickerIndicatorIsAlwaysVisible = true;
360    container->appendChild(PickerIndicatorElement::create(document, *this));
361    m_pickerIndicatorIsVisible = true;
362    updatePickerIndicatorVisibility();
363}
364
365void BaseMultipleFieldsDateAndTimeInputType::destroyShadowSubtree()
366{
367    ASSERT(!m_isDestroyingShadowSubtree);
368    m_isDestroyingShadowSubtree = true;
369    if (SpinButtonElement* element = spinButtonElement())
370        element->removeSpinButtonOwner();
371    if (ClearButtonElement* element = clearButtonElement())
372        element->removeClearButtonOwner();
373    if (DateTimeEditElement* element = dateTimeEditElement())
374        element->removeEditControlOwner();
375    if (PickerIndicatorElement* element = pickerIndicatorElement())
376        element->removePickerIndicatorOwner();
377
378    // If a field element has focus, set focus back to the <input> itself before
379    // deleting the field. This prevents unnecessary focusout/blur events.
380    if (containsFocusedShadowElement())
381        element().focus();
382
383    BaseDateAndTimeInputType::destroyShadowSubtree();
384    m_isDestroyingShadowSubtree = false;
385}
386
387void BaseMultipleFieldsDateAndTimeInputType::handleFocusEvent(Element* oldFocusedElement, FocusType type)
388{
389    DateTimeEditElement* edit = dateTimeEditElement();
390    if (!edit || m_isDestroyingShadowSubtree)
391        return;
392    if (type == FocusTypeBackward) {
393        if (element().document().page())
394            element().document().page()->focusController().advanceFocus(type);
395    } else if (type == FocusTypeNone || type == FocusTypeMouse || type == FocusTypePage) {
396        edit->focusByOwner(oldFocusedElement);
397    } else {
398        edit->focusByOwner();
399    }
400}
401
402void BaseMultipleFieldsDateAndTimeInputType::forwardEvent(Event* event)
403{
404    if (SpinButtonElement* element = spinButtonElement()) {
405        element->forwardEvent(event);
406        if (event->defaultHandled())
407            return;
408    }
409
410    if (DateTimeEditElement* edit = dateTimeEditElement())
411        edit->defaultEventHandler(event);
412}
413
414void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged()
415{
416    spinButtonElement()->releaseCapture();
417    clearButtonElement()->releaseCapture();
418    if (DateTimeEditElement* edit = dateTimeEditElement())
419        edit->disabledStateChanged();
420}
421
422void BaseMultipleFieldsDateAndTimeInputType::requiredAttributeChanged()
423{
424    clearButtonElement()->releaseCapture();
425    updateClearButtonVisibility();
426}
427
428void BaseMultipleFieldsDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event)
429{
430    if (m_pickerIndicatorIsVisible
431        && ((event->keyIdentifier() == "Down" && event->getModifierState("Alt")) || (RenderTheme::theme().shouldOpenPickerWithF4Key() && event->keyIdentifier() == "F4"))) {
432        if (PickerIndicatorElement* element = pickerIndicatorElement())
433            element->openPopup();
434        event->setDefaultHandled();
435    } else {
436        forwardEvent(event);
437    }
438}
439
440bool BaseMultipleFieldsDateAndTimeInputType::hasBadInput() const
441{
442    DateTimeEditElement* edit = dateTimeEditElement();
443    return element().value().isEmpty() && edit && edit->anyEditableFieldsHaveValues();
444}
445
446AtomicString BaseMultipleFieldsDateAndTimeInputType::localeIdentifier() const
447{
448    return element().computeInheritedLanguage();
449}
450
451void BaseMultipleFieldsDateAndTimeInputType::editControlDidChangeValueByKeyboard()
452{
453    element().dispatchFormControlChangeEvent();
454}
455
456void BaseMultipleFieldsDateAndTimeInputType::minOrMaxAttributeChanged()
457{
458    updateView();
459}
460
461void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged()
462{
463    spinButtonElement()->releaseCapture();
464    clearButtonElement()->releaseCapture();
465    if (DateTimeEditElement* edit = dateTimeEditElement())
466        edit->readOnlyStateChanged();
467}
468
469void BaseMultipleFieldsDateAndTimeInputType::restoreFormControlState(const FormControlState& state)
470{
471    DateTimeEditElement* edit = dateTimeEditElement();
472    if (!edit)
473        return;
474    DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state);
475    edit->setValueAsDateTimeFieldsState(dateTimeFieldsState);
476    element().setValueInternal(sanitizeValue(edit->value()), DispatchNoEvent);
477    updateClearButtonVisibility();
478}
479
480FormControlState BaseMultipleFieldsDateAndTimeInputType::saveFormControlState() const
481{
482    if (DateTimeEditElement* edit = dateTimeEditElement())
483        return edit->valueAsDateTimeFieldsState().saveFormControlState();
484    return FormControlState();
485}
486
487void BaseMultipleFieldsDateAndTimeInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
488{
489    InputType::setValue(sanitizedValue, valueChanged, eventBehavior);
490    DateTimeEditElement* edit = dateTimeEditElement();
491    if (valueChanged || (sanitizedValue.isEmpty() && edit && edit->anyEditableFieldsHaveValues())) {
492        element().updateView();
493        element().setNeedsValidityCheck();
494    }
495}
496
497bool BaseMultipleFieldsDateAndTimeInputType::shouldUseInputMethod() const
498{
499    return false;
500}
501
502void BaseMultipleFieldsDateAndTimeInputType::stepAttributeChanged()
503{
504    updateView();
505}
506
507void BaseMultipleFieldsDateAndTimeInputType::updateView()
508{
509    DateTimeEditElement* edit = dateTimeEditElement();
510    if (!edit)
511        return;
512
513    DateTimeEditElement::LayoutParameters layoutParameters(element().locale(), createStepRange(AnyIsDefaultStep));
514
515    DateComponents date;
516    bool hasValue = false;
517    if (!element().suggestedValue().isNull())
518        hasValue = parseToDateComponents(element().suggestedValue(), &date);
519    else
520        hasValue = parseToDateComponents(element().value(), &date);
521    if (!hasValue)
522        setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date);
523
524    setupLayoutParameters(layoutParameters, date);
525
526    DEFINE_STATIC_LOCAL(AtomicString, datetimeformatAttr, ("datetimeformat", AtomicString::ConstructFromLiteral));
527    edit->setAttribute(datetimeformatAttr, AtomicString(layoutParameters.dateTimeFormat), ASSERT_NO_EXCEPTION);
528    const AtomicString pattern = edit->fastGetAttribute(HTMLNames::patternAttr);
529    if (!pattern.isEmpty())
530        layoutParameters.dateTimeFormat = pattern;
531
532    if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this))
533        layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat;
534
535    if (hasValue)
536        edit->setValueAsDate(layoutParameters, date);
537    else
538        edit->setEmptyValue(layoutParameters, date);
539    updateClearButtonVisibility();
540}
541
542void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged()
543{
544    if (!element().hasDirtyValue())
545        updateView();
546}
547
548void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged()
549{
550    updatePickerIndicatorVisibility();
551}
552
553void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility()
554{
555    if (m_pickerIndicatorIsAlwaysVisible) {
556        showPickerIndicator();
557        return;
558    }
559    if (element().hasValidDataListOptions())
560        showPickerIndicator();
561    else
562        hidePickerIndicator();
563}
564
565void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator()
566{
567    if (!m_pickerIndicatorIsVisible)
568        return;
569    m_pickerIndicatorIsVisible = false;
570    ASSERT(pickerIndicatorElement());
571    pickerIndicatorElement()->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
572}
573
574void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator()
575{
576    if (m_pickerIndicatorIsVisible)
577        return;
578    m_pickerIndicatorIsVisible = true;
579    ASSERT(pickerIndicatorElement());
580    pickerIndicatorElement()->removeInlineStyleProperty(CSSPropertyDisplay);
581}
582
583bool BaseMultipleFieldsDateAndTimeInputType::shouldHaveSecondField(const DateComponents& date) const
584{
585    StepRange stepRange = createStepRange(AnyIsDefaultStep);
586    return date.second() || date.millisecond()
587        || !stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero()
588        || !stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero();
589}
590
591void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner()
592{
593    element().focus();
594}
595
596bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents()
597{
598    return !element().isDisabledOrReadOnly() && !element().isRequired();
599}
600
601void BaseMultipleFieldsDateAndTimeInputType::clearValue()
602{
603    RefPtrWillBeRawPtr<HTMLInputElement> input(element());
604    input->setValue("", DispatchInputAndChangeEvent);
605    input->updateClearButtonVisibility();
606}
607
608void BaseMultipleFieldsDateAndTimeInputType::updateClearButtonVisibility()
609{
610    ClearButtonElement* clearButton = clearButtonElement();
611    if (!clearButton)
612        return;
613
614    if (element().isRequired() || !dateTimeEditElement()->anyEditableFieldsHaveValues()) {
615        clearButton->setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
616        clearButton->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone);
617    } else {
618        clearButton->removeInlineStyleProperty(CSSPropertyOpacity);
619        clearButton->removeInlineStyleProperty(CSSPropertyPointerEvents);
620    }
621}
622
623} // namespace WebCore
624
625#endif
626