Upstream version 7.36.149.0
[platform/framework/web/crosswalk.git] / src / third_party / WebKit / Source / core / html / forms / BaseMultipleFieldsDateAndTimeInputType.cpp
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/events/ScopedEventQueue.h"
40 #include "core/html/HTMLDataListElement.h"
41 #include "core/html/HTMLInputElement.h"
42 #include "core/html/HTMLOptionElement.h"
43 #include "core/html/forms/DateTimeFieldsState.h"
44 #include "core/html/forms/FormController.h"
45 #include "core/html/shadow/ShadowElementNames.h"
46 #include "core/page/FocusController.h"
47 #include "core/page/Page.h"
48 #include "core/rendering/RenderTheme.h"
49 #include "platform/DateComponents.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     RefPtr<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     RefPtr<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     RefPtr<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