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 "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 
     54 namespace WebCore {
     55 
     56 class DateTimeFormatValidator : public DateTimeFormat::TokenHandler {
     57 public:
     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 
     73 private:
     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 
     84 void 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 
    123 bool 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 
    130 DateTimeEditElement* BaseMultipleFieldsDateAndTimeInputType::dateTimeEditElement() const
    131 {
    132     return toDateTimeEditElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::dateTimeEdit()));
    133 }
    134 
    135 SpinButtonElement* BaseMultipleFieldsDateAndTimeInputType::spinButtonElement() const
    136 {
    137     return toSpinButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::spinButton()));
    138 }
    139 
    140 ClearButtonElement* BaseMultipleFieldsDateAndTimeInputType::clearButtonElement() const
    141 {
    142     return toClearButtonElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::clearButton()));
    143 }
    144 
    145 PickerIndicatorElement* BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorElement() const
    146 {
    147     return toPickerIndicatorElement(element().userAgentShadowRoot()->getElementById(ShadowElementNames::pickerIndicator()));
    148 }
    149 
    150 inline bool BaseMultipleFieldsDateAndTimeInputType::containsFocusedShadowElement() const
    151 {
    152     return element().userAgentShadowRoot()->contains(element().document().focusedElement());
    153 }
    154 
    155 void 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 
    170 void 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 
    182 void 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 
    199 bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const
    200 {
    201     return false;
    202 }
    203 
    204 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerDisabled() const
    205 {
    206     return element().isDisabledFormControl();
    207 }
    208 
    209 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerReadOnly() const
    210 {
    211     return element().isReadOnly();
    212 }
    213 
    214 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectSpinButtonOwner()
    215 {
    216     if (DateTimeEditElement* edit = dateTimeEditElement())
    217         edit->focusIfNoFocus();
    218 }
    219 
    220 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToMouseEvents()
    221 {
    222     return !element().isDisabledOrReadOnly();
    223 }
    224 
    225 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToWheelEvents()
    226 {
    227     if (!shouldSpinButtonRespondToMouseEvents())
    228         return false;
    229     if (DateTimeEditElement* edit = dateTimeEditElement())
    230         return edit->hasFocusedField();
    231     return false;
    232 }
    233 
    234 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepDown()
    235 {
    236     if (DateTimeEditElement* edit = dateTimeEditElement())
    237         edit->stepDown();
    238 }
    239 
    240 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepUp()
    241 {
    242     if (DateTimeEditElement* edit = dateTimeEditElement())
    243         edit->stepUp();
    244 }
    245 
    246 void BaseMultipleFieldsDateAndTimeInputType::spinButtonDidReleaseMouseCapture(SpinButtonElement::EventDispatch eventDispatch)
    247 {
    248     if (eventDispatch == SpinButtonElement::EventDispatchAllowed)
    249         element().dispatchFormControlChangeEvent();
    250 }
    251 
    252 bool BaseMultipleFieldsDateAndTimeInputType::isPickerIndicatorOwnerDisabledOrReadOnly() const
    253 {
    254     return element().isDisabledOrReadOnly();
    255 }
    256 
    257 void 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 
    274 void 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 
    283 bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
    284 {
    285     return element().setupDateTimeChooserParameters(parameters);
    286 }
    287 
    288 BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element)
    289     : BaseDateAndTimeInputType(element)
    290     , m_isDestroyingShadowSubtree(false)
    291     , m_pickerIndicatorIsVisible(false)
    292     , m_pickerIndicatorIsAlwaysVisible(false)
    293 {
    294 }
    295 
    296 BaseMultipleFieldsDateAndTimeInputType::~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 
    310 String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
    311 {
    312     return locale().queryString(blink::WebLocalizedString::ValidationBadInputForDateTime);
    313 }
    314 
    315 void BaseMultipleFieldsDateAndTimeInputType::blur()
    316 {
    317     if (DateTimeEditElement* edit = dateTimeEditElement())
    318         edit->blurByOwner();
    319 }
    320 
    321 PassRefPtr<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 
    340 void 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 
    365 void 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 
    387 void 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 
    402 void 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 
    414 void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged()
    415 {
    416     spinButtonElement()->releaseCapture();
    417     clearButtonElement()->releaseCapture();
    418     if (DateTimeEditElement* edit = dateTimeEditElement())
    419         edit->disabledStateChanged();
    420 }
    421 
    422 void BaseMultipleFieldsDateAndTimeInputType::requiredAttributeChanged()
    423 {
    424     clearButtonElement()->releaseCapture();
    425     updateClearButtonVisibility();
    426 }
    427 
    428 void 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 
    440 bool BaseMultipleFieldsDateAndTimeInputType::hasBadInput() const
    441 {
    442     DateTimeEditElement* edit = dateTimeEditElement();
    443     return element().value().isEmpty() && edit && edit->anyEditableFieldsHaveValues();
    444 }
    445 
    446 AtomicString BaseMultipleFieldsDateAndTimeInputType::localeIdentifier() const
    447 {
    448     return element().computeInheritedLanguage();
    449 }
    450 
    451 void BaseMultipleFieldsDateAndTimeInputType::editControlDidChangeValueByKeyboard()
    452 {
    453     element().dispatchFormControlChangeEvent();
    454 }
    455 
    456 void BaseMultipleFieldsDateAndTimeInputType::minOrMaxAttributeChanged()
    457 {
    458     updateView();
    459 }
    460 
    461 void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged()
    462 {
    463     spinButtonElement()->releaseCapture();
    464     clearButtonElement()->releaseCapture();
    465     if (DateTimeEditElement* edit = dateTimeEditElement())
    466         edit->readOnlyStateChanged();
    467 }
    468 
    469 void 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 
    480 FormControlState BaseMultipleFieldsDateAndTimeInputType::saveFormControlState() const
    481 {
    482     if (DateTimeEditElement* edit = dateTimeEditElement())
    483         return edit->valueAsDateTimeFieldsState().saveFormControlState();
    484     return FormControlState();
    485 }
    486 
    487 void 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 
    497 bool BaseMultipleFieldsDateAndTimeInputType::shouldUseInputMethod() const
    498 {
    499     return false;
    500 }
    501 
    502 void BaseMultipleFieldsDateAndTimeInputType::stepAttributeChanged()
    503 {
    504     updateView();
    505 }
    506 
    507 void 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 
    542 void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged()
    543 {
    544     if (!element().hasDirtyValue())
    545         updateView();
    546 }
    547 
    548 void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged()
    549 {
    550     updatePickerIndicatorVisibility();
    551 }
    552 
    553 void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility()
    554 {
    555     if (m_pickerIndicatorIsAlwaysVisible) {
    556         showPickerIndicator();
    557         return;
    558     }
    559     if (element().hasValidDataListOptions())
    560         showPickerIndicator();
    561     else
    562         hidePickerIndicator();
    563 }
    564 
    565 void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator()
    566 {
    567     if (!m_pickerIndicatorIsVisible)
    568         return;
    569     m_pickerIndicatorIsVisible = false;
    570     ASSERT(pickerIndicatorElement());
    571     pickerIndicatorElement()->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
    572 }
    573 
    574 void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator()
    575 {
    576     if (m_pickerIndicatorIsVisible)
    577         return;
    578     m_pickerIndicatorIsVisible = true;
    579     ASSERT(pickerIndicatorElement());
    580     pickerIndicatorElement()->removeInlineStyleProperty(CSSPropertyDisplay);
    581 }
    582 
    583 bool 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 
    591 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner()
    592 {
    593     element().focus();
    594 }
    595 
    596 bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents()
    597 {
    598     return !element().isDisabledOrReadOnly() && !element().isRequired();
    599 }
    600 
    601 void BaseMultipleFieldsDateAndTimeInputType::clearValue()
    602 {
    603     RefPtrWillBeRawPtr<HTMLInputElement> input(element());
    604     input->setValue("", DispatchInputAndChangeEvent);
    605     input->updateClearButtonVisibility();
    606 }
    607 
    608 void 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