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