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 blink {
     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     EventQueueScope scope;
    268     DateComponents date;
    269     unsigned end;
    270     if (date.parseDate(value, 0, end) && end == value.length())
    271         edit->setOnlyYearMonthDay(date);
    272     element().dispatchFormControlChangeEvent();
    273 }
    274 
    275 void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(double value)
    276 {
    277     ASSERT(std::isfinite(value) || std::isnan(value));
    278     if (std::isnan(value))
    279         element().setValue(emptyString(), DispatchInputAndChangeEvent);
    280     else
    281         element().setValueAsNumber(value, ASSERT_NO_EXCEPTION, DispatchInputAndChangeEvent);
    282 }
    283 
    284 Element& BaseMultipleFieldsDateAndTimeInputType::pickerOwnerElement() const
    285 {
    286     return element();
    287 }
    288 
    289 bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
    290 {
    291     return element().setupDateTimeChooserParameters(parameters);
    292 }
    293 
    294 BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element)
    295     : BaseDateAndTimeInputType(element)
    296     , m_isDestroyingShadowSubtree(false)
    297     , m_pickerIndicatorIsVisible(false)
    298     , m_pickerIndicatorIsAlwaysVisible(false)
    299 {
    300 }
    301 
    302 BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType()
    303 {
    304 #if !ENABLE(OILPAN)
    305     if (SpinButtonElement* element = spinButtonElement())
    306         element->removeSpinButtonOwner();
    307     if (ClearButtonElement* element = clearButtonElement())
    308         element->removeClearButtonOwner();
    309     if (DateTimeEditElement* element = dateTimeEditElement())
    310         element->removeEditControlOwner();
    311     if (PickerIndicatorElement* element = pickerIndicatorElement())
    312         element->removePickerIndicatorOwner();
    313 #endif
    314 }
    315 
    316 String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
    317 {
    318     return locale().queryString(blink::WebLocalizedString::ValidationBadInputForDateTime);
    319 }
    320 
    321 void BaseMultipleFieldsDateAndTimeInputType::blur()
    322 {
    323     if (DateTimeEditElement* edit = dateTimeEditElement())
    324         edit->blurByOwner();
    325 }
    326 
    327 PassRefPtr<RenderStyle> BaseMultipleFieldsDateAndTimeInputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)
    328 {
    329     EDisplay originalDisplay = originalStyle->display();
    330     EDisplay newDisplay = originalDisplay;
    331     if (originalDisplay == INLINE || originalDisplay == INLINE_BLOCK)
    332         newDisplay = INLINE_FLEX;
    333     else if (originalDisplay == BLOCK)
    334         newDisplay = FLEX;
    335     TextDirection contentDirection = computedTextDirection();
    336     if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay)
    337         return originalStyle;
    338 
    339     RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
    340     style->setDirection(contentDirection);
    341     style->setDisplay(newDisplay);
    342     style->setUnique();
    343     return style.release();
    344 }
    345 
    346 void BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree()
    347 {
    348     ASSERT(element().shadow());
    349 
    350     // Element must not have a renderer here, because if it did
    351     // DateTimeEditElement::customStyleForRenderer() is called in appendChild()
    352     // before the field wrapper element is created.
    353     // FIXME: This code should not depend on such craziness.
    354     ASSERT(!element().renderer());
    355 
    356     Document& document = element().document();
    357     ContainerNode* container = element().userAgentShadowRoot();
    358 
    359     container->appendChild(DateTimeEditElement::create(document, *this));
    360     element().updateView();
    361     container->appendChild(ClearButtonElement::create(document, *this));
    362     container->appendChild(SpinButtonElement::create(document, *this));
    363 
    364     if (RenderTheme::theme().supportsCalendarPicker(formControlType()))
    365         m_pickerIndicatorIsAlwaysVisible = true;
    366     container->appendChild(PickerIndicatorElement::create(document, *this));
    367     m_pickerIndicatorIsVisible = true;
    368     updatePickerIndicatorVisibility();
    369 }
    370 
    371 void BaseMultipleFieldsDateAndTimeInputType::destroyShadowSubtree()
    372 {
    373     ASSERT(!m_isDestroyingShadowSubtree);
    374     m_isDestroyingShadowSubtree = true;
    375     if (SpinButtonElement* element = spinButtonElement())
    376         element->removeSpinButtonOwner();
    377     if (ClearButtonElement* element = clearButtonElement())
    378         element->removeClearButtonOwner();
    379     if (DateTimeEditElement* element = dateTimeEditElement())
    380         element->removeEditControlOwner();
    381     if (PickerIndicatorElement* element = pickerIndicatorElement())
    382         element->removePickerIndicatorOwner();
    383 
    384     // If a field element has focus, set focus back to the <input> itself before
    385     // deleting the field. This prevents unnecessary focusout/blur events.
    386     if (containsFocusedShadowElement())
    387         element().focus();
    388 
    389     BaseDateAndTimeInputType::destroyShadowSubtree();
    390     m_isDestroyingShadowSubtree = false;
    391 }
    392 
    393 void BaseMultipleFieldsDateAndTimeInputType::handleFocusInEvent(Element* oldFocusedElement, FocusType type)
    394 {
    395     DateTimeEditElement* edit = dateTimeEditElement();
    396     if (!edit || m_isDestroyingShadowSubtree)
    397         return;
    398     if (type == FocusTypeBackward) {
    399         if (element().document().page())
    400             element().document().page()->focusController().advanceFocus(type);
    401     } else if (type == FocusTypeNone || type == FocusTypeMouse || type == FocusTypePage) {
    402         edit->focusByOwner(oldFocusedElement);
    403     } else {
    404         edit->focusByOwner();
    405     }
    406 }
    407 
    408 void BaseMultipleFieldsDateAndTimeInputType::forwardEvent(Event* event)
    409 {
    410     if (SpinButtonElement* element = spinButtonElement()) {
    411         element->forwardEvent(event);
    412         if (event->defaultHandled())
    413             return;
    414     }
    415 
    416     if (DateTimeEditElement* edit = dateTimeEditElement())
    417         edit->defaultEventHandler(event);
    418 }
    419 
    420 void BaseMultipleFieldsDateAndTimeInputType::disabledAttributeChanged()
    421 {
    422     spinButtonElement()->releaseCapture();
    423     clearButtonElement()->releaseCapture();
    424     if (DateTimeEditElement* edit = dateTimeEditElement())
    425         edit->disabledStateChanged();
    426 }
    427 
    428 void BaseMultipleFieldsDateAndTimeInputType::requiredAttributeChanged()
    429 {
    430     clearButtonElement()->releaseCapture();
    431     updateClearButtonVisibility();
    432 }
    433 
    434 void BaseMultipleFieldsDateAndTimeInputType::handleKeydownEvent(KeyboardEvent* event)
    435 {
    436     if (m_pickerIndicatorIsVisible
    437         && ((event->keyIdentifier() == "Down" && event->getModifierState("Alt")) || (RenderTheme::theme().shouldOpenPickerWithF4Key() && event->keyIdentifier() == "F4"))) {
    438         if (PickerIndicatorElement* element = pickerIndicatorElement())
    439             element->openPopup();
    440         event->setDefaultHandled();
    441     } else {
    442         forwardEvent(event);
    443     }
    444 }
    445 
    446 bool BaseMultipleFieldsDateAndTimeInputType::hasBadInput() const
    447 {
    448     DateTimeEditElement* edit = dateTimeEditElement();
    449     return element().value().isEmpty() && edit && edit->anyEditableFieldsHaveValues();
    450 }
    451 
    452 AtomicString BaseMultipleFieldsDateAndTimeInputType::localeIdentifier() const
    453 {
    454     return element().computeInheritedLanguage();
    455 }
    456 
    457 void BaseMultipleFieldsDateAndTimeInputType::editControlDidChangeValueByKeyboard()
    458 {
    459     element().dispatchFormControlChangeEvent();
    460 }
    461 
    462 void BaseMultipleFieldsDateAndTimeInputType::minOrMaxAttributeChanged()
    463 {
    464     updateView();
    465 }
    466 
    467 void BaseMultipleFieldsDateAndTimeInputType::readonlyAttributeChanged()
    468 {
    469     spinButtonElement()->releaseCapture();
    470     clearButtonElement()->releaseCapture();
    471     if (DateTimeEditElement* edit = dateTimeEditElement())
    472         edit->readOnlyStateChanged();
    473 }
    474 
    475 void BaseMultipleFieldsDateAndTimeInputType::restoreFormControlState(const FormControlState& state)
    476 {
    477     DateTimeEditElement* edit = dateTimeEditElement();
    478     if (!edit)
    479         return;
    480     DateTimeFieldsState dateTimeFieldsState = DateTimeFieldsState::restoreFormControlState(state);
    481     edit->setValueAsDateTimeFieldsState(dateTimeFieldsState);
    482     element().setValueInternal(sanitizeValue(edit->value()), DispatchNoEvent);
    483     updateClearButtonVisibility();
    484 }
    485 
    486 FormControlState BaseMultipleFieldsDateAndTimeInputType::saveFormControlState() const
    487 {
    488     if (DateTimeEditElement* edit = dateTimeEditElement())
    489         return edit->valueAsDateTimeFieldsState().saveFormControlState();
    490     return FormControlState();
    491 }
    492 
    493 void BaseMultipleFieldsDateAndTimeInputType::setValue(const String& sanitizedValue, bool valueChanged, TextFieldEventBehavior eventBehavior)
    494 {
    495     InputType::setValue(sanitizedValue, valueChanged, eventBehavior);
    496     DateTimeEditElement* edit = dateTimeEditElement();
    497     if (valueChanged || (sanitizedValue.isEmpty() && edit && edit->anyEditableFieldsHaveValues())) {
    498         element().updateView();
    499         element().setNeedsValidityCheck();
    500     }
    501 }
    502 
    503 void BaseMultipleFieldsDateAndTimeInputType::stepAttributeChanged()
    504 {
    505     updateView();
    506 }
    507 
    508 void BaseMultipleFieldsDateAndTimeInputType::updateView()
    509 {
    510     DateTimeEditElement* edit = dateTimeEditElement();
    511     if (!edit)
    512         return;
    513 
    514     DateTimeEditElement::LayoutParameters layoutParameters(element().locale(), createStepRange(AnyIsDefaultStep));
    515 
    516     DateComponents date;
    517     bool hasValue = false;
    518     if (!element().suggestedValue().isNull())
    519         hasValue = parseToDateComponents(element().suggestedValue(), &date);
    520     else
    521         hasValue = parseToDateComponents(element().value(), &date);
    522     if (!hasValue)
    523         setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date);
    524 
    525     setupLayoutParameters(layoutParameters, date);
    526 
    527     DEFINE_STATIC_LOCAL(AtomicString, datetimeformatAttr, ("datetimeformat", AtomicString::ConstructFromLiteral));
    528     edit->setAttribute(datetimeformatAttr, AtomicString(layoutParameters.dateTimeFormat), ASSERT_NO_EXCEPTION);
    529     const AtomicString pattern = edit->fastGetAttribute(HTMLNames::patternAttr);
    530     if (!pattern.isEmpty())
    531         layoutParameters.dateTimeFormat = pattern;
    532 
    533     if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this))
    534         layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat;
    535 
    536     if (hasValue)
    537         edit->setValueAsDate(layoutParameters, date);
    538     else
    539         edit->setEmptyValue(layoutParameters, date);
    540     updateClearButtonVisibility();
    541 }
    542 
    543 void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged()
    544 {
    545     if (!element().hasDirtyValue())
    546         updateView();
    547 }
    548 
    549 void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged()
    550 {
    551     updatePickerIndicatorVisibility();
    552 }
    553 
    554 void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility()
    555 {
    556     if (m_pickerIndicatorIsAlwaysVisible) {
    557         showPickerIndicator();
    558         return;
    559     }
    560     if (element().hasValidDataListOptions())
    561         showPickerIndicator();
    562     else
    563         hidePickerIndicator();
    564 }
    565 
    566 void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator()
    567 {
    568     if (!m_pickerIndicatorIsVisible)
    569         return;
    570     m_pickerIndicatorIsVisible = false;
    571     ASSERT(pickerIndicatorElement());
    572     pickerIndicatorElement()->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
    573 }
    574 
    575 void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator()
    576 {
    577     if (m_pickerIndicatorIsVisible)
    578         return;
    579     m_pickerIndicatorIsVisible = true;
    580     ASSERT(pickerIndicatorElement());
    581     pickerIndicatorElement()->removeInlineStyleProperty(CSSPropertyDisplay);
    582 }
    583 
    584 bool BaseMultipleFieldsDateAndTimeInputType::shouldHaveSecondField(const DateComponents& date) const
    585 {
    586     StepRange stepRange = createStepRange(AnyIsDefaultStep);
    587     return date.second() || date.millisecond()
    588         || !stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero()
    589         || !stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero();
    590 }
    591 
    592 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner()
    593 {
    594     element().focus();
    595 }
    596 
    597 bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents()
    598 {
    599     return !element().isDisabledOrReadOnly() && !element().isRequired();
    600 }
    601 
    602 void BaseMultipleFieldsDateAndTimeInputType::clearValue()
    603 {
    604     RefPtrWillBeRawPtr<HTMLInputElement> input(element());
    605     input->setValue("", DispatchInputAndChangeEvent);
    606     input->updateClearButtonVisibility();
    607 }
    608 
    609 void BaseMultipleFieldsDateAndTimeInputType::updateClearButtonVisibility()
    610 {
    611     ClearButtonElement* clearButton = clearButtonElement();
    612     if (!clearButton)
    613         return;
    614 
    615     if (element().isRequired() || !dateTimeEditElement()->anyEditableFieldsHaveValues()) {
    616         clearButton->setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
    617         clearButton->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone);
    618     } else {
    619         clearButton->removeInlineStyleProperty(CSSPropertyOpacity);
    620         clearButton->removeInlineStyleProperty(CSSPropertyPointerEvents);
    621     }
    622 }
    623 
    624 TextDirection BaseMultipleFieldsDateAndTimeInputType::computedTextDirection()
    625 {
    626     return element().locale().isRTL() ? RTL : LTR;
    627 }
    628 
    629 AXObject* BaseMultipleFieldsDateAndTimeInputType::popupRootAXObject()
    630 {
    631     if (PickerIndicatorElement* picker = pickerIndicatorElement())
    632         return picker->popupRootAXObject();
    633     return 0;
    634 }
    635 
    636 } // namespace blink
    637 
    638 #endif
    639