8771e9f8a5e5a451c71bd670ab401e8ab0e4ada4
[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/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     }
191     input->notifyFormStateChanged();
192     input->updateClearButtonVisibility();
193 }
194
195 bool BaseMultipleFieldsDateAndTimeInputType::hasCustomFocusLogic() const
196 {
197     return false;
198 }
199
200 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerDisabled() const
201 {
202     return element().isDisabledFormControl();
203 }
204
205 bool BaseMultipleFieldsDateAndTimeInputType::isEditControlOwnerReadOnly() const
206 {
207     return element().isReadOnly();
208 }
209
210 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectSpinButtonOwner()
211 {
212     if (DateTimeEditElement* edit = dateTimeEditElement())
213         edit->focusIfNoFocus();
214 }
215
216 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToMouseEvents()
217 {
218     return !element().isDisabledOrReadOnly();
219 }
220
221 bool BaseMultipleFieldsDateAndTimeInputType::shouldSpinButtonRespondToWheelEvents()
222 {
223     if (!shouldSpinButtonRespondToMouseEvents())
224         return false;
225     if (DateTimeEditElement* edit = dateTimeEditElement())
226         return edit->hasFocusedField();
227     return false;
228 }
229
230 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepDown()
231 {
232     if (DateTimeEditElement* edit = dateTimeEditElement())
233         edit->stepDown();
234 }
235
236 void BaseMultipleFieldsDateAndTimeInputType::spinButtonStepUp()
237 {
238     if (DateTimeEditElement* edit = dateTimeEditElement())
239         edit->stepUp();
240 }
241
242 void BaseMultipleFieldsDateAndTimeInputType::spinButtonDidReleaseMouseCapture()
243 {
244     element().dispatchFormControlChangeEvent();
245 }
246
247 bool BaseMultipleFieldsDateAndTimeInputType::isPickerIndicatorOwnerDisabledOrReadOnly() const
248 {
249     return element().isDisabledOrReadOnly();
250 }
251
252 void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(const String& value)
253 {
254     if (element().isValidValue(value)) {
255         element().setValue(value, DispatchInputAndChangeEvent);
256         return;
257     }
258
259     DateTimeEditElement* edit = this->dateTimeEditElement();
260     if (!edit)
261         return;
262     DateComponents date;
263     unsigned end;
264     if (date.parseDate(value, 0, end) && end == value.length())
265         edit->setOnlyYearMonthDay(date);
266     element().dispatchFormControlChangeEvent();
267 }
268
269 void BaseMultipleFieldsDateAndTimeInputType::pickerIndicatorChooseValue(double value)
270 {
271     ASSERT(std::isfinite(value) || std::isnan(value));
272     if (std::isnan(value))
273         element().setValue(emptyString(), DispatchInputAndChangeEvent);
274     else
275         element().setValueAsNumber(value, ASSERT_NO_EXCEPTION, DispatchInputAndChangeEvent);
276 }
277
278 bool BaseMultipleFieldsDateAndTimeInputType::setupDateTimeChooserParameters(DateTimeChooserParameters& parameters)
279 {
280     return element().setupDateTimeChooserParameters(parameters);
281 }
282
283 BaseMultipleFieldsDateAndTimeInputType::BaseMultipleFieldsDateAndTimeInputType(HTMLInputElement& element)
284     : BaseDateAndTimeInputType(element)
285     , m_isDestroyingShadowSubtree(false)
286     , m_pickerIndicatorIsVisible(false)
287     , m_pickerIndicatorIsAlwaysVisible(false)
288 {
289 }
290
291 BaseMultipleFieldsDateAndTimeInputType::~BaseMultipleFieldsDateAndTimeInputType()
292 {
293     if (SpinButtonElement* element = spinButtonElement())
294         element->removeSpinButtonOwner();
295     if (ClearButtonElement* element = clearButtonElement())
296         element->removeClearButtonOwner();
297     if (DateTimeEditElement* element = dateTimeEditElement())
298         element->removeEditControlOwner();
299     if (PickerIndicatorElement* element = pickerIndicatorElement())
300         element->removePickerIndicatorOwner();
301 }
302
303 String BaseMultipleFieldsDateAndTimeInputType::badInputText() const
304 {
305     return locale().queryString(blink::WebLocalizedString::ValidationBadInputForDateTime);
306 }
307
308 void BaseMultipleFieldsDateAndTimeInputType::blur()
309 {
310     if (DateTimeEditElement* edit = dateTimeEditElement())
311         edit->blurByOwner();
312 }
313
314 PassRefPtr<RenderStyle> BaseMultipleFieldsDateAndTimeInputType::customStyleForRenderer(PassRefPtr<RenderStyle> originalStyle)
315 {
316     EDisplay originalDisplay = originalStyle->display();
317     EDisplay newDisplay = originalDisplay;
318     if (originalDisplay == INLINE || originalDisplay == INLINE_BLOCK)
319         newDisplay = INLINE_FLEX;
320     else if (originalDisplay == BLOCK)
321         newDisplay = FLEX;
322     TextDirection contentDirection = element().locale().isRTL() ? RTL : LTR;
323     if (originalStyle->direction() == contentDirection && originalDisplay == newDisplay)
324         return originalStyle;
325
326     RefPtr<RenderStyle> style = RenderStyle::clone(originalStyle.get());
327     style->setDirection(contentDirection);
328     style->setDisplay(newDisplay);
329     style->setUnique();
330     return style.release();
331 }
332
333 void BaseMultipleFieldsDateAndTimeInputType::createShadowSubtree()
334 {
335     ASSERT(element().shadow());
336
337     // Element must not have a renderer here, because if it did
338     // DateTimeEditElement::customStyleForRenderer() is called in appendChild()
339     // before the field wrapper element is created.
340     // FIXME: This code should not depend on such craziness.
341     ASSERT(!element().renderer());
342
343     Document& document = element().document();
344     ContainerNode* container = element().userAgentShadowRoot();
345
346     container->appendChild(DateTimeEditElement::create(document, *this));
347     updateView();
348     container->appendChild(ClearButtonElement::create(document, *this));
349     container->appendChild(SpinButtonElement::create(document, *this));
350
351     bool shouldAddPickerIndicator = false;
352     if (InputType::themeSupportsDataListUI(this))
353         shouldAddPickerIndicator = true;
354     if (RenderTheme::theme().supportsCalendarPicker(formControlType())) {
355         shouldAddPickerIndicator = true;
356         m_pickerIndicatorIsAlwaysVisible = true;
357     }
358     if (shouldAddPickerIndicator) {
359         container->appendChild(PickerIndicatorElement::create(document, *this));
360         m_pickerIndicatorIsVisible = true;
361         updatePickerIndicatorVisibility();
362     }
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, FocusDirection direction)
388 {
389     DateTimeEditElement* edit = dateTimeEditElement();
390     if (!edit || m_isDestroyingShadowSubtree)
391         return;
392     if (direction == FocusDirectionBackward) {
393         if (element().document().page())
394             element().document().page()->focusController().advanceFocus(direction);
395     } else if (direction == FocusDirectionNone || direction == FocusDirectionMouse || direction == FocusDirectionPage) {
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         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     const bool hasValue = parseToDateComponents(element().value(), &date);
517     if (!hasValue)
518         setMillisecondToDateComponents(layoutParameters.stepRange.minimum().toDouble(), &date);
519
520     setupLayoutParameters(layoutParameters, date);
521
522     const AtomicString pattern = edit->fastGetAttribute(HTMLNames::patternAttr);
523     if (!pattern.isEmpty())
524         layoutParameters.dateTimeFormat = pattern;
525
526     if (!DateTimeFormatValidator().validateFormat(layoutParameters.dateTimeFormat, *this))
527         layoutParameters.dateTimeFormat = layoutParameters.fallbackDateTimeFormat;
528
529     if (hasValue)
530         edit->setValueAsDate(layoutParameters, date);
531     else
532         edit->setEmptyValue(layoutParameters, date);
533     updateClearButtonVisibility();
534 }
535
536 void BaseMultipleFieldsDateAndTimeInputType::valueAttributeChanged()
537 {
538     if (!element().hasDirtyValue())
539         updateView();
540 }
541
542 void BaseMultipleFieldsDateAndTimeInputType::listAttributeTargetChanged()
543 {
544     updatePickerIndicatorVisibility();
545 }
546
547 void BaseMultipleFieldsDateAndTimeInputType::updatePickerIndicatorVisibility()
548 {
549     if (m_pickerIndicatorIsAlwaysVisible) {
550         showPickerIndicator();
551         return;
552     }
553     if (RuntimeEnabledFeatures::dataListElementEnabled()) {
554         if (element().hasValidDataListOptions())
555             showPickerIndicator();
556         else
557             hidePickerIndicator();
558     }
559 }
560
561 void BaseMultipleFieldsDateAndTimeInputType::hidePickerIndicator()
562 {
563     if (!m_pickerIndicatorIsVisible)
564         return;
565     m_pickerIndicatorIsVisible = false;
566     ASSERT(pickerIndicatorElement());
567     pickerIndicatorElement()->setInlineStyleProperty(CSSPropertyDisplay, CSSValueNone);
568 }
569
570 void BaseMultipleFieldsDateAndTimeInputType::showPickerIndicator()
571 {
572     if (m_pickerIndicatorIsVisible)
573         return;
574     m_pickerIndicatorIsVisible = true;
575     ASSERT(pickerIndicatorElement());
576     pickerIndicatorElement()->removeInlineStyleProperty(CSSPropertyDisplay);
577 }
578
579 bool BaseMultipleFieldsDateAndTimeInputType::shouldHaveSecondField(const DateComponents& date) const
580 {
581     StepRange stepRange = createStepRange(AnyIsDefaultStep);
582     return date.second() || date.millisecond()
583         || !stepRange.minimum().remainder(static_cast<int>(msPerMinute)).isZero()
584         || !stepRange.step().remainder(static_cast<int>(msPerMinute)).isZero();
585 }
586
587 void BaseMultipleFieldsDateAndTimeInputType::focusAndSelectClearButtonOwner()
588 {
589     element().focus();
590 }
591
592 bool BaseMultipleFieldsDateAndTimeInputType::shouldClearButtonRespondToMouseEvents()
593 {
594     return !element().isDisabledOrReadOnly() && !element().isRequired();
595 }
596
597 void BaseMultipleFieldsDateAndTimeInputType::clearValue()
598 {
599     RefPtr<HTMLInputElement> input(element());
600     input->setValue("", DispatchInputAndChangeEvent);
601     input->updateClearButtonVisibility();
602 }
603
604 void BaseMultipleFieldsDateAndTimeInputType::updateClearButtonVisibility()
605 {
606     ClearButtonElement* clearButton = clearButtonElement();
607     if (!clearButton)
608         return;
609
610     if (element().isRequired() || !dateTimeEditElement()->anyEditableFieldsHaveValues()) {
611         clearButton->setInlineStyleProperty(CSSPropertyOpacity, 0.0, CSSPrimitiveValue::CSS_NUMBER);
612         clearButton->setInlineStyleProperty(CSSPropertyPointerEvents, CSSValueNone);
613     } else {
614         clearButton->removeInlineStyleProperty(CSSPropertyOpacity);
615         clearButton->removeInlineStyleProperty(CSSPropertyPointerEvents);
616     }
617 }
618
619 } // namespace WebCore
620
621 #endif